[CommonItemStack] Add mimicAsType API
Signed-off-by: Irmo van den Berge <irmo.vandenberge@ziggo.nl>
This commit is contained in:
1 parent
c8ac83787a
commit
c327d6f72b
6 files changed
+162
-18
No files matched your search
+4
@@ -63,7 +63,9 @@ public abstract class ItemStackHandle extends Template.Handle {
|
||||
public abstract void setFireworksFlightDuration(int duration);
|
||||
public abstract GameProfileHandle getSkullProfile();
|
||||
public abstract void setSkullProfile(GameProfileHandle profile);
|
||||
public abstract boolean hasItemModelSet();
|
||||
public abstract MinecraftKeyHandle getItemModel();
|
||||
public abstract MinecraftKeyHandle getItemModelIfSet();
|
||||
public abstract void setItemModel(MinecraftKeyHandle key);
|
||||
public abstract boolean hasCustomModelData();
|
||||
public abstract boolean hasCustomModelDataValue();
|
||||
@@ -143,7 +145,9 @@ public abstract class ItemStackHandle extends Template.Handle {
|
||||
public final Template.Method<Void> setFireworksFlightDuration = new Template.Method<Void>();
|
||||
public final Template.Method.Converted<GameProfileHandle> getSkullProfile = new Template.Method.Converted<GameProfileHandle>();
|
||||
public final Template.Method.Converted<Void> setSkullProfile = new Template.Method.Converted<Void>();
|
||||
public final Template.Method<Boolean> hasItemModelSet = new Template.Method<Boolean>();
|
||||
public final Template.Method.Converted<MinecraftKeyHandle> getItemModel = new Template.Method.Converted<MinecraftKeyHandle>();
|
||||
public final Template.Method.Converted<MinecraftKeyHandle> getItemModelIfSet = new Template.Method.Converted<MinecraftKeyHandle>();
|
||||
public final Template.Method.Converted<Void> setItemModel = new Template.Method.Converted<Void>();
|
||||
public final Template.Method<Boolean> hasCustomModelData = new Template.Method<Boolean>();
|
||||
public final Template.Method<Boolean> hasCustomModelDataValue = new Template.Method<Boolean>();
|
||||
|
||||
@@ -69,7 +69,8 @@ public class Common {
|
||||
"Common:NBTUtil:LoadSaveEquipment",
|
||||
"Common:NBT:ChatTextSerialization",
|
||||
"Module:RegionFlagTracker",
|
||||
"Common:CommonItemStack:ItemModel"
|
||||
"Common:CommonItemStack:ItemModel",
|
||||
"Common:CommonItemStack:MimicAsType"
|
||||
).collect(Collectors.toSet());
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bergerkiller.bukkit.common.inventory;
|
||||
|
||||
import com.bergerkiller.bukkit.common.internal.CommonCapabilities;
|
||||
import com.bergerkiller.bukkit.common.internal.CommonNMS;
|
||||
import com.bergerkiller.bukkit.common.map.util.ModelInfoLookup;
|
||||
import com.bergerkiller.bukkit.common.nbt.CommonTagCompound;
|
||||
@@ -716,20 +717,36 @@ public final class CommonItemStack implements Cloneable {
|
||||
*/
|
||||
public boolean hasItemModel() {
|
||||
return getHandle(true)
|
||||
.map(ItemStackHandle::getItemModel)
|
||||
.isPresent();
|
||||
.map(ItemStackHandle::hasItemModelSet)
|
||||
.orElse(Boolean.FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item model set for this item. If none are set and it defaults
|
||||
* to the vanilla item model, returns <i>null</i>
|
||||
* to the vanilla item model, returns the name of this vanilla item model.
|
||||
*
|
||||
* @return set item model, or <i>null</i> if not set
|
||||
* @see ModelInfoLookup#lookupVanillaItemModel(CommonItemStack)
|
||||
*/
|
||||
public MinecraftKeyHandle getItemModel() {
|
||||
if (CommonCapabilities.HAS_ITEM_MODEL_COMPONENT) {
|
||||
return getHandle(true)
|
||||
.map(ItemStackHandle::getItemModel)
|
||||
.orElseGet(() -> ModelInfoLookup.lookupVanillaItemModel(this));
|
||||
} else {
|
||||
return ModelInfoLookup.lookupVanillaItemModel(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item model set for this item. If none are set and it defaults
|
||||
* to the vanilla item model, returns <i>empty</i>
|
||||
*
|
||||
* @return set item model, or <i>empty</i> if not set
|
||||
*/
|
||||
public Optional<MinecraftKeyHandle> getItemModelIfSet() {
|
||||
return getHandle(true)
|
||||
.map(ItemStackHandle::getItemModel)
|
||||
.orElse(null);
|
||||
.map(ItemStackHandle::getItemModelIfSet);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -762,6 +779,41 @@ public final class CommonItemStack implements Cloneable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link #setItemModel(String) item model} of this item to the type currently set,
|
||||
* and sets the type of this item to the type specified, if item models are supported. This
|
||||
* makes this item have the game behavior of the input type while still looking like (mimicing)
|
||||
* the original type.<br>
|
||||
* <br>
|
||||
* If the server version is older than 1.21.2 this method does nothing, as item models are not
|
||||
* supported there.<br>
|
||||
* <br>
|
||||
* <b>Use: </b>Call this method when creating new "tool" items to make them behave like a different
|
||||
* item than is displayed. This can for example prevent block items from triggering block placement
|
||||
* by the player.
|
||||
*
|
||||
* @param type Material Type to set on this item, that the game will use the behavior of
|
||||
* @return this CommonItemStack
|
||||
*/
|
||||
public CommonItemStack mimicAsType(Material type) {
|
||||
if (CommonCapabilities.HAS_ITEM_MODEL_COMPONENT) {
|
||||
MinecraftKeyHandle itemModel = this.getItemModel();
|
||||
setType(type);
|
||||
setItemModel(itemModel);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this version of the server supports setting a custom item model override
|
||||
* on items. If false, then {@link #setItemModel(MinecraftKeyHandle)} is a no-op.
|
||||
*
|
||||
* @return True if item models can be set on items
|
||||
*/
|
||||
public static boolean canSetItemModel() {
|
||||
return CommonCapabilities.HAS_ITEM_MODEL_COMPONENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this item stores a custom model data integer value, which controls
|
||||
* client-side display of models. Since Minecraft 1.14.
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.Optional;
|
||||
* This is needed because Minecraft is really stupid sometimes
|
||||
*/
|
||||
public class ModelInfoLookup {
|
||||
private static final MinecraftKeyHandle MISSING_MODEL_NAME = MinecraftKeyHandle.createNew("minecraft", "builtin/missing");
|
||||
private static final Map<Material, List<ModelNameEntry>> byMaterial = new EnumMap<>(Material.class);
|
||||
private static final Map<String, ModelNameEntry> byItemName = new HashMap<>();
|
||||
private static final Map<String, ModelNameEntry> byBlockName = new HashMap<>();
|
||||
@@ -227,28 +228,37 @@ public class ModelInfoLookup {
|
||||
}
|
||||
|
||||
public static String lookupItem(CommonItemStack itemStack) {
|
||||
// Check for an item-model data component override
|
||||
{
|
||||
MinecraftKeyHandle itemModel = itemStack.getItemModel();
|
||||
if (itemModel != null) {
|
||||
if (itemModel.getNamespace().equals("minecraft")) {
|
||||
return itemModel.getName();
|
||||
} else {
|
||||
return itemModel.toString();
|
||||
}
|
||||
}
|
||||
MinecraftKeyHandle itemModel = itemStack.getItemModel();
|
||||
if (itemModel.getNamespace().equals("minecraft")) {
|
||||
return itemModel.getName();
|
||||
} else {
|
||||
return itemModel.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the item model name of an item, completely ignoring the item model
|
||||
* data component. This is mostly for internal use.
|
||||
*
|
||||
* @param itemStack CommonItemStack
|
||||
* @return Set item model name key
|
||||
*/
|
||||
public static MinecraftKeyHandle lookupVanillaItemModel(CommonItemStack itemStack) {
|
||||
return lookupItemModelNameEntry(itemStack).getItemNameKey()
|
||||
.orElse(MISSING_MODEL_NAME);
|
||||
}
|
||||
|
||||
private static ModelNameEntry lookupItemModelNameEntry(CommonItemStack itemStack) {
|
||||
List<ModelNameEntry> entries = byMaterial.get(itemStack.getType());
|
||||
if (entries.size() > 1) {
|
||||
// Got to match it to the item
|
||||
for (ModelNameEntry entry : entries) {
|
||||
if (entry.matchDynamicItem(itemStack)) {
|
||||
return entry.getItemName().orElse("unknown");
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return entries.get(0).getItemName().orElse("unknown");
|
||||
return entries.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,6 +276,11 @@ public class ModelInfoLookup {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<MinecraftKeyHandle> getItemNameKey() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getBlockName() {
|
||||
return Optional.empty();
|
||||
@@ -291,6 +306,13 @@ public class ModelInfoLookup {
|
||||
*/
|
||||
Optional<String> getItemName();
|
||||
|
||||
/**
|
||||
* Gets the {@link #getItemName()} but as an encoded MinecraftKey
|
||||
*
|
||||
* @return Item model name as MinecraftKey
|
||||
*/
|
||||
Optional<MinecraftKeyHandle> getItemNameKey();
|
||||
|
||||
/**
|
||||
* Returns the block name, if this entry has a block
|
||||
*
|
||||
@@ -347,6 +369,7 @@ public class ModelInfoLookup {
|
||||
private final Material inkSacMaterial;
|
||||
private final int damageValue;
|
||||
private final String itemName;
|
||||
private final MinecraftKeyHandle itemNameKey;
|
||||
|
||||
public static List<ModelNameEntry> createLegacyInkSacMaterials(Material inkSacItemMaterial) {
|
||||
return Arrays.asList(
|
||||
@@ -373,6 +396,7 @@ public class ModelInfoLookup {
|
||||
this.inkSacMaterial = inkSacMaterial;
|
||||
this.damageValue = damageValue;
|
||||
this.itemName = "dye_" + colorName;
|
||||
this.itemNameKey = MinecraftKeyHandle.createNew("minecraft", this.itemName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -385,6 +409,11 @@ public class ModelInfoLookup {
|
||||
return Optional.of(itemName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<MinecraftKeyHandle> getItemNameKey() {
|
||||
return Optional.of(itemNameKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getBlockName() {
|
||||
return Optional.empty();
|
||||
@@ -409,6 +438,7 @@ public class ModelInfoLookup {
|
||||
private final Material fishItemMaterial;
|
||||
private final int damageValue;
|
||||
private final String itemName;
|
||||
private final MinecraftKeyHandle itemNameKey;
|
||||
|
||||
public static List<ModelNameEntry> createLegacyFishMaterials(Material fishItemMaterial, boolean cooked) {
|
||||
return Arrays.asList(
|
||||
@@ -423,6 +453,7 @@ public class ModelInfoLookup {
|
||||
this.fishItemMaterial = fishItemMaterial;
|
||||
this.damageValue = damageValue;
|
||||
this.itemName = (cooked ? "cooked_" : "") + fishName;
|
||||
this.itemNameKey = MinecraftKeyHandle.createNew("minecraft", this.itemName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -435,6 +466,11 @@ public class ModelInfoLookup {
|
||||
return Optional.of(itemName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<MinecraftKeyHandle> getItemNameKey() {
|
||||
return Optional.of(itemNameKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getBlockName() {
|
||||
return Optional.empty();
|
||||
@@ -459,11 +495,13 @@ public class ModelInfoLookup {
|
||||
private static class ItemModelNameEntry implements ModelNameEntry {
|
||||
public final Material itemMaterial;
|
||||
public final String itemName;
|
||||
private final MinecraftKeyHandle itemNameKey;
|
||||
|
||||
// Note: only for non-block materials!
|
||||
public ItemModelNameEntry(Material itemMaterial) {
|
||||
this.itemMaterial = itemMaterial;
|
||||
this.itemName = lookupItemResourceName(itemMaterial);
|
||||
this.itemNameKey = MinecraftKeyHandle.createNew("minecraft", this.itemName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -476,6 +514,11 @@ public class ModelInfoLookup {
|
||||
return Optional.of(itemName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<MinecraftKeyHandle> getItemNameKey() {
|
||||
return Optional.of(itemNameKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getBlockName() {
|
||||
return Optional.empty();
|
||||
@@ -517,6 +560,7 @@ public class ModelInfoLookup {
|
||||
public final BlockData blockData;
|
||||
public final String blockName;
|
||||
public final String itemName;
|
||||
public final MinecraftKeyHandle itemNameKey;
|
||||
|
||||
public BlockDataModelNameEntry(BlockData blockData) {
|
||||
this.blockData = blockData;
|
||||
@@ -532,6 +576,7 @@ public class ModelInfoLookup {
|
||||
} else {
|
||||
itemName = blockName;
|
||||
}
|
||||
itemNameKey = MinecraftKeyHandle.createNew("minecraft", itemName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -544,6 +589,11 @@ public class ModelInfoLookup {
|
||||
return Optional.of(itemName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<MinecraftKeyHandle> getItemNameKey() {
|
||||
return Optional.of(itemNameKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getBlockName() {
|
||||
return Optional.of(blockName);
|
||||
|
||||
@@ -793,10 +793,22 @@ class ItemStack {
|
||||
}
|
||||
|
||||
#if version >= 1.21.2
|
||||
public boolean hasItemModelSet() {
|
||||
return instance.hasNonDefault(DataComponents.ITEM_MODEL);
|
||||
}
|
||||
|
||||
public (MinecraftKeyHandle) MinecraftKey getItemModel() {
|
||||
return (MinecraftKey) instance.get(DataComponents.ITEM_MODEL);
|
||||
}
|
||||
|
||||
public (MinecraftKeyHandle) MinecraftKey getItemModelIfSet() {
|
||||
if (instance.hasNonDefault(DataComponents.ITEM_MODEL)) {
|
||||
return (MinecraftKey) instance.get(DataComponents.ITEM_MODEL);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setItemModel((MinecraftKeyHandle) MinecraftKey key) {
|
||||
if (key != null) {
|
||||
instance.set(DataComponents.ITEM_MODEL, key);
|
||||
@@ -805,10 +817,18 @@ class ItemStack {
|
||||
}
|
||||
}
|
||||
#else
|
||||
public boolean hasItemModelSet() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public (MinecraftKeyHandle) MinecraftKey getItemModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public (MinecraftKeyHandle) MinecraftKey getItemModelIfSet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setItemModel((MinecraftKeyHandle) MinecraftKey key) {
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bergerkiller.bukkit.common;
|
||||
|
||||
import com.bergerkiller.bukkit.common.inventory.CommonItemMaterials;
|
||||
import com.bergerkiller.bukkit.common.inventory.CommonItemStack;
|
||||
import com.bergerkiller.bukkit.common.inventory.InventoryBaseImpl;
|
||||
import com.bergerkiller.bukkit.common.nbt.CommonTagCompound;
|
||||
@@ -19,6 +20,22 @@ import static org.junit.Assert.*;
|
||||
|
||||
public class CommonItemStackTest {
|
||||
|
||||
@Test
|
||||
public void testMimicAsType() {
|
||||
if (!CommonItemStack.canSetItemModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CommonItemStack item = CommonItemStack.create(MaterialUtil.getFirst("DIAMOND_SWORD", "LEGACY_DIAMOND_SWORD"), 1);
|
||||
System.out.println(item.getItemModel());
|
||||
assertFalse(item.hasItemModel());
|
||||
|
||||
item.mimicAsType(CommonItemMaterials.STICK); // Hits like a wet noodle
|
||||
|
||||
assertEquals(CommonItemMaterials.STICK, item.getType());
|
||||
assertEquals("minecraft:diamond_sword", item.getItemModel().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVanillaDisplayName() {
|
||||
// Note: display name is a translatable, which we decode into English.
|
||||
|
||||
Reference in new issue
Block a user