Skip to content

Commit

Permalink
NBT handling update: EntityTag & attributes (#2622)
Browse files Browse the repository at this point in the history
* Replace `EntityTag` nbt usage

* Replace attribute NBT stuff with API

* Renames

* Rename x2
  • Loading branch information
tal5 committed May 17, 2024
1 parent 5ecb388 commit d37d034
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 228 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
Expand Down Expand Up @@ -47,6 +48,26 @@ public abstract class ItemHelper {

public abstract ItemStack setNbtData(ItemStack itemStack, CompoundTag compoundTag);

public CompoundTag getEntityData(ItemStack item) { // TODO: once 1.20 is the minimum supported version, remove default impl
CompoundTag nbt = getNbtData(item);
return nbt != null && nbt.getValue().get("EntityTag") instanceof CompoundTag entityNbt ? entityNbt : null;
}

public ItemStack setEntityData(ItemStack item, CompoundTag entityNbt, EntityType entityType) { // TODO: once 1.20 is the minimum supported version, remove default impl
boolean shouldRemove = entityNbt == null || entityNbt.isEmpty();
CompoundTag nbt = getNbtData(item);
if (shouldRemove && !nbt.containsKey("EntityTag")) {
return item;
}
if (shouldRemove) {
nbt = nbt.createBuilder().remove("EntityTag").build();
}
else {
nbt = nbt.createBuilder().put("EntityTag", entityNbt).build();
}
return setNbtData(item, nbt);
}

public abstract void registerSmithingRecipe(String keyName, ItemStack result, ItemStack[] baseItem, boolean baseExact, ItemStack[] upgradeItem, boolean upgradeExact, ItemStack[] templateItem, boolean templateExact);

public abstract void setInventoryItem(Inventory inventory, ItemStack item, int slot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ public boolean containsKey(String key) {
return value.containsKey(key);
}

public boolean isEmpty() {
return getValue().isEmpty();
}

public int size() {
return getValue().size();
}

@Override
public Map<String, Tag> getValue() {
return value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.denizenscript.denizencore.objects.core.MapTag;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;

import java.util.ArrayList;
Expand All @@ -31,15 +32,11 @@ public static boolean describes(ItemTag item) {

@Override
public MapTag getPropertyValue() {
CompoundTag compoundTag = NMSHandler.itemHelper.getNbtData(getItemStack());
if (compoundTag == null) {
CompoundTag entityNbt = NMSHandler.itemHelper.getEntityData(getItemStack());
if (entityNbt == null) {
return null;
}
Tag entPart = compoundTag.getValue().get("EntityTag");
if (!(entPart instanceof CompoundTag)) {
return null;
}
Tag posePart = ((CompoundTag) entPart).getValue().get("Pose");
Tag posePart = entityNbt.getValue().get("Pose");
if (!(posePart instanceof CompoundTag)) {
return null;
}
Expand All @@ -56,15 +53,10 @@ public MapTag getPropertyValue() {

@Override
public void setPropertyValue(MapTag param, Mechanism mechanism) {
CompoundTag compoundTag = NMSHandler.itemHelper.getNbtData(getItemStack());
Tag entPart, posePart;
CompoundTag entityNbt = NMSHandler.itemHelper.getEntityData(getItemStack());
if (mechanism.hasValue()) {
if (compoundTag == null) {
compoundTag = new CompoundTagBuilder().build();
}
entPart = compoundTag.getValue().get("EntityTag");
if (!(entPart instanceof CompoundTag)) {
entPart = new CompoundTagBuilder().build();
if (entityNbt == null) {
entityNbt = new CompoundTagBuilder().build();
}
CompoundTagBuilder poseBuilder = new CompoundTagBuilder();
procMechKey(mechanism, poseBuilder, "Head", "head", param);
Expand All @@ -75,33 +67,22 @@ public void setPropertyValue(MapTag param, Mechanism mechanism) {
procMechKey(mechanism, poseBuilder, "RightLeg", "right_leg", param);
CompoundTag pose = poseBuilder.build();
if (pose.getValue().isEmpty()) {
entPart = ((CompoundTag) entPart).createBuilder().remove("Pose").build();
entityNbt = entityNbt.createBuilder().remove("Pose").build();
}
else {
entPart = ((CompoundTag) entPart).createBuilder().put("Pose", pose).build();
entityNbt = entityNbt.createBuilder().put("Pose", pose).build();
}
}
else {
if (compoundTag == null) {
return;
}
entPart = compoundTag.getValue().get("EntityTag");
if (!(entPart instanceof CompoundTag)) {
if (entityNbt == null) {
return;
}
posePart = ((CompoundTag) entPart).getValue().get("Pose");
if (!(posePart instanceof CompoundTag)) {
if (!(entityNbt.getValue().get("Pose") instanceof CompoundTag)) {
return;
}
entPart = ((CompoundTag) entPart).createBuilder().remove("Pose").build();
}
if (((CompoundTag) entPart).getValue().isEmpty()) {
compoundTag = compoundTag.createBuilder().remove("EntityTag").build();
}
else {
compoundTag = compoundTag.createBuilder().put("EntityTag", entPart).build();
entityNbt = entityNbt.createBuilder().remove("Pose").build();
}
ItemStack result = NMSHandler.itemHelper.setNbtData(getItemStack(), compoundTag);
ItemStack result = NMSHandler.itemHelper.setEntityData(getItemStack(), entityNbt, EntityType.ARMOR_STAND);
setItemStack(result);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
package com.denizenscript.denizen.objects.properties.item;

import com.denizenscript.denizen.utilities.nbt.CustomNBT;
import com.denizenscript.denizen.objects.ItemTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizen.utilities.BukkitImplDeprecations;
import com.denizenscript.denizencore.objects.Mechanism;
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.objects.properties.Property;
import com.denizenscript.denizencore.tags.Attribute;
import com.denizenscript.denizencore.tags.core.EscapeTagUtil;
import com.denizenscript.denizen.utilities.BukkitImplDeprecations;
import com.denizenscript.denizencore.utilities.AsciiMatcher;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;

import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Deprecated
public class ItemAttributeNBT implements Property {
Expand Down Expand Up @@ -62,12 +70,15 @@ public ObjectTag getObjectAttribute(Attribute attribute) {

public ListTag getList() {
ItemStack itemStack = item.getItemStack();
List<CustomNBT.AttributeReturn> nbtKeys = CustomNBT.getAttributes(itemStack);
ItemMeta meta = itemStack.getItemMeta();
ListTag list = new ListTag();
if (nbtKeys != null) {
for (CustomNBT.AttributeReturn atr : nbtKeys) {
list.add(EscapeTagUtil.escape(atr.attr) + "/" + EscapeTagUtil.escape(atr.slot) + "/" + atr.op + "/" + atr.amt);
}
if (meta == null || !meta.hasAttributeModifiers()) {
return list;
}
for (Map.Entry<org.bukkit.attribute.Attribute, AttributeModifier> entry : meta.getAttributeModifiers().entries()) {
AttributeModifier modifier = entry.getValue();
String slotName = toLegacyName(modifier.getSlot() != null ? modifier.getSlot() : EquipmentSlot.HAND);
list.add(EscapeTagUtil.escape(entry.getKey().getKey().getKey()) + "/" + EscapeTagUtil.escape(slotName) + "/" + modifier.getOperation().ordinal() + "/" + modifier.getAmount());
}
return list;
}
Expand All @@ -93,20 +104,92 @@ public void adjust(Mechanism mechanism) {
}
ListTag list = mechanism.valueAsType(ListTag.class);
ItemStack itemStack = item.getItemStack();
itemStack = CustomNBT.clearNBT(itemStack, CustomNBT.KEY_ATTRIBUTES);
ItemMeta meta = itemStack.getItemMeta();
if (meta.hasAttributeModifiers()) {
meta.getAttributeModifiers().keySet().forEach(meta::removeAttributeModifier);
}
for (String string : list) {
String[] split = string.split("/");
if (split.length != 4) {
mechanism.echoError("Invalid nbt_attributes input: must have 4 values per attribute.");
continue;
}
String attribute = EscapeTagUtil.unEscape(split[0]);
String attribute = fixAttributeName1_16(EscapeTagUtil.unEscape(split[0]));
String slot = EscapeTagUtil.unEscape(split[1]);
int op = new ElementTag(split[2]).asInt();
double amt = new ElementTag(split[3]).asDouble();
itemStack = CustomNBT.addAttribute(itemStack, attribute, slot, op, amt);
long uuidhelp = uuidChoice(itemStack);
int attribsSize = meta.hasAttributeModifiers() ? meta.getAttributeModifiers().values().size() : 0;
UUID fullUuid = new UUID(uuidhelp + 88512 + attribsSize, uuidhelp * 2 + 1250025L + attribsSize);
meta.addAttributeModifier(Registry.ATTRIBUTE.get(NamespacedKey.minecraft(attribute)), new AttributeModifier(fullUuid, attribute, amt, AttributeModifier.Operation.values()[op], fromLegacyName(slot)));
}
itemStack.setItemMeta(meta);
item.setItemStack(itemStack);
}
}

public static final AsciiMatcher uppercaseMatcher = new AsciiMatcher(AsciiMatcher.LETTERS_UPPER);

public static final HashMap<String, String> attributeNameUpdates = new HashMap<>();

static {
attributeNameUpdates.put("generic.maxHealth", "generic.max_health");
attributeNameUpdates.put("generic.followRange", "generic.follow_range");
attributeNameUpdates.put("generic.knockbackResistance", "generic.knockback_resistance");
attributeNameUpdates.put("generic.movementSpeed", "generic.movement_speed");
attributeNameUpdates.put("generic.flyingSpeed", "generic.flying_speed");
attributeNameUpdates.put("generic.attackDamage", "generic.attack_damage");
attributeNameUpdates.put("generic.attackKnockback", "generic.attack_knockback");
attributeNameUpdates.put("generic.attackSpeed", "generic.attack_speed");
attributeNameUpdates.put("generic.armorToughness", "generic.armor_toughness");
}

public static String fixAttributeName1_16(String input) {
if (!uppercaseMatcher.containsAnyMatch(input)) {
return input;
}
String replacement = attributeNameUpdates.get(input);
if (replacement != null) {
return replacement;
}
return CoreUtilities.toLowerCase(input);
}

public static long uuidChoice(ItemStack its) {
String mat = CoreUtilities.toLowerCase(its.getType().name());
if (mat.contains("boots")) {
return 1000;
}
else if (mat.contains("legging")) {
return 100000;
}
else if (mat.contains("helmet")) {
return 10000000;
}
else if (mat.contains("chestp")) {
return 1000000000;
}
else {
return 1;
}
}

private static EquipmentSlot fromLegacyName(String name) {
return switch (name) {
case "mainhand" -> EquipmentSlot.HAND;
case "offhand" -> EquipmentSlot.OFF_HAND;
default -> {
EquipmentSlot slot = ElementTag.asEnum(EquipmentSlot.class, name);
yield slot != null ? slot : EquipmentSlot.HAND;
}
};
}

private static String toLegacyName(EquipmentSlot slot) {
return switch (slot) {
case HAND -> "mainhand";
case OFF_HAND -> "offhand";
default -> CoreUtilities.toLowerCase(slot.name());
};
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
package com.denizenscript.denizen.objects.properties.item;

import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.nms.util.jnbt.ByteTag;
import com.denizenscript.denizen.nms.util.jnbt.CompoundTag;
import com.denizenscript.denizen.nms.util.jnbt.Tag;
import com.denizenscript.denizen.nms.util.jnbt.CompoundTagBuilder;
import com.denizenscript.denizen.objects.ItemTag;
import com.denizenscript.denizencore.objects.Mechanism;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.properties.Property;
import com.denizenscript.denizencore.tags.Attribute;
import org.bukkit.Material;

import java.util.LinkedHashMap;
import java.util.Map;
import org.bukkit.entity.EntityType;

public class ItemFrameInvisible implements Property {

Expand Down Expand Up @@ -45,15 +42,11 @@ public ItemFrameInvisible(ItemTag item) {
ItemTag item;

public boolean isInvisible() {
CompoundTag compoundTag = NMSHandler.itemHelper.getNbtData(item.getItemStack());
if (compoundTag == null) {
return false;
}
CompoundTag entTag = (CompoundTag) compoundTag.getValue().get("EntityTag");
if (entTag == null) {
CompoundTag entityNbt = NMSHandler.itemHelper.getEntityData(item.getItemStack());
if (entityNbt == null) {
return false;
}
byte b = entTag.getByte("Invisible");
byte b = entityNbt.getByte("Invisible");
return b == 1;
}

Expand Down Expand Up @@ -101,30 +94,19 @@ public void adjust(Mechanism mechanism) {
// <ItemTag.invisible>
// -->
if (mechanism.matches("invisible") && mechanism.requireBoolean()) {
CompoundTag compoundTag = NMSHandler.itemHelper.getNbtData(item.getItemStack());
Map<String, Tag> result = new LinkedHashMap<>(compoundTag.getValue());
CompoundTag entityTag = (CompoundTag) result.get("EntityTag");
Map<String, Tag> entMap;
if (entityTag != null) {
entMap = new LinkedHashMap<>(entityTag.getValue());
}
else {
entMap = new LinkedHashMap<>();
}
if (mechanism.getValue().asBoolean()) {
entMap.put("Invisible", new ByteTag((byte) 1));
}
else {
entMap.remove("Invisible");
CompoundTag entityNbt = NMSHandler.itemHelper.getEntityData(item.getItemStack());
boolean invisible = mechanism.getValue().asBoolean();
if (!invisible && entityNbt == null) {
return;
}
if (entMap.isEmpty()) {
result.remove("EntityTag");
if (invisible) {
CompoundTagBuilder builder = entityNbt != null ? entityNbt.createBuilder() : CompoundTagBuilder.create();
entityNbt = builder.putByte("Invisible", (byte) 1).build();
}
else {
result.put("EntityTag", NMSHandler.instance.createCompoundTag(entMap));
entityNbt = entityNbt.createBuilder().remove("Invisible").build();
}
compoundTag = NMSHandler.instance.createCompoundTag(result);
item.setItemStack(NMSHandler.itemHelper.setNbtData(item.getItemStack(), compoundTag));
item.setItemStack(NMSHandler.itemHelper.setEntityData(item.getItemStack(), entityNbt, item.getBukkitMaterial() == Material.ITEM_FRAME ? EntityType.ITEM_FRAME : EntityType.GLOW_ITEM_FRAME));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ public class BukkitImplDeprecations {
public static Warning oldStructureTypes = new SlowWarning("oldStructureTypes", "'server.structure_types' is based on outdated API and doesn't support modern datapack features. Use 'server.structures' instead.");
public static Warning findStructureTags = new SlowWarning("findStructureTags", "'LocationTag.find.structure' and related tags are deprecated in favor of 'LocationTag.find_structure'.");

// Added 2021/03/29, made very-slow 2022/12/31, made slow 2024/05/09.
// 2022-year-end commonality: #7
// 2023-year-end commonality: #31
public static Warning legacyAttributeProperties = new SlowWarning("legacyAttributeProperties", "The 'attribute' properties are deprecated in favor of the 'attribute_modifiers' properties which more fully implement the attribute system.");

// ==================== VERY SLOW deprecations ====================
// These are only shown minimally, so server owners are aware of them but not bugged by them. Only servers with active scripters (using 'ex reload') will see them often.

Expand Down Expand Up @@ -257,11 +262,6 @@ public class BukkitImplDeprecations {
// 2022-year-end commonality: #10
public static Warning entityMechanismsFormat = new VerySlowWarning("entityMechanismsFormat", "Entity script containers previously allowed mechanisms in the script's root, however they should now be under a 'mechanisms' key.");

// Added 2021/03/29, made very-slow 2022/12/31.
// 2022-year-end commonality: #7
// 2023-year-end commonality: #31
public static Warning legacyAttributeProperties = new VerySlowWarning("legacyAttributeProperties", "The 'attribute' properties are deprecated in favor of the 'attribute_modifiers' properties which more fully implement the attribute system.");

// Added 2021/08/30, made very-slow 2022/12/31.
// 2022-year-end commonality: #23
public static Warning takeMoney = new VerySlowWarning("takeMoney", "Using the 'take' command to take money is deprecated in favor of the 'money' command.");
Expand Down

0 comments on commit d37d034

Please sign in to comment.