From 36f3ed3131f1b0a9fa05b66013ac8d09e38ef6ef Mon Sep 17 00:00:00 2001 From: Alex 'mcmonkey' Goodwin Date: Sun, 24 Oct 2021 07:11:27 -0700 Subject: [PATCH] item.armor_pose and entity.armor_pose rework --- .../objects/properties/PropertyRegistry.java | 1 + .../properties/entity/EntityArmorPose.java | 113 +++++----- .../properties/item/ItemArmorPose.java | 194 ++++++++++++++++++ .../objects/properties/item/ItemRawNBT.java | 17 +- 4 files changed, 272 insertions(+), 53 deletions(-) create mode 100644 plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemArmorPose.java diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java index 8065bd399b..d1970b4e0e 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java @@ -133,6 +133,7 @@ public static void registerMainProperties() { PropertyParser.registerProperty(InventoryUniquifier.class, InventoryTag.class); // register core ItemTag properties + PropertyParser.registerProperty(ItemArmorPose.class, ItemTag.class); PropertyParser.registerProperty(ItemAttributeModifiers.class, ItemTag.class); PropertyParser.registerProperty(ItemAttributeNBT.class, ItemTag.class); PropertyParser.registerProperty(ItemBaseColor.class, ItemTag.class); diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityArmorPose.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityArmorPose.java index fd22bd1e3b..4167203ba7 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityArmorPose.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityArmorPose.java @@ -5,14 +5,18 @@ 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.MapTag; import com.denizenscript.denizencore.objects.properties.Property; -import com.denizenscript.denizencore.tags.Attribute; +import com.denizenscript.denizencore.objects.properties.PropertyParser; import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.Deprecations; +import com.denizenscript.denizencore.utilities.text.StringHolder; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.EntityType; import org.bukkit.util.EulerAngle; import java.util.Iterator; +import java.util.Map; public class EntityArmorPose implements Property { @@ -30,10 +34,6 @@ public static EntityArmorPose getFrom(ObjectTag entity) { } } - public static final String[] handledTags = new String[] { - "armor_pose_list", "armor_pose" - }; - public static final String[] handledMechs = new String[] { "armor_pose" }; @@ -46,7 +46,7 @@ private EntityArmorPose(EntityTag ent) { @Override public String getPropertyString() { - return getPoseList().identify(); + return getPoseMap().identify(); } @Override @@ -64,39 +64,41 @@ private ListTag getPoseList() { return list; } - @Override - public ObjectTag getObjectAttribute(Attribute attribute) { - - if (attribute == null) { - return null; + public MapTag getPoseMap() { + ArmorStand armorStand = (ArmorStand) entity.getBukkitEntity(); + MapTag map = new MapTag(); + for (PosePart posePart : PosePart.values()) { + map.putObject(CoreUtilities.toLowerCase(posePart.name()), fromEulerAngle(posePart.getAngle(armorStand))); } + return map; + } - // <--[tag] - // @attribute - // @returns ListTag - // @mechanism EntityTag.armor_pose - // @group attributes - // @description - // Returns a list of all poses and angles for the armor stand in the - // format: PART|ANGLE|... - // For example, head|4.5,3,4.5|body|5.4,3.2,1 - // Angles are in radians! - // --> - if (attribute.startsWith("armor_pose_list")) { - return getPoseList().getObjectAttribute(attribute.fulfill(1)); - } + public static void registerTags() { // <--[tag] - // @attribute ]> - // @returns LocationTag + // @attribute + // @returns MapTag // @mechanism EntityTag.armor_pose // @group attributes // @description - // Returns the current angle pose for the specified part. - // Valid parts: HEAD, BODY, LEFT_ARM, RIGHT_ARM, LEFT_LEG, RIGHT_LEG + // Returns a map of all poses and angles for the armor stand. + // For example, head=4.5,3,4.5;body=5.4,3.2,1 // Angles are in radians! // --> - else if (attribute.startsWith("armor_pose") && attribute.hasContext(1)) { + PropertyParser.registerTag(MapTag.class, "armor_pose_map", (attribute, entity) -> { + return entity.getPoseMap(); + }); + + PropertyParser.registerTag(ListTag.class, "armor_pose_list", (attribute, entity) -> { + Deprecations.entityArmorPose.warn(attribute.context); + return entity.getPoseList(); + }); + + PropertyParser.registerTag(LocationTag.class, "armor_pose", (attribute, entity) -> { + Deprecations.entityArmorPose.warn(attribute.context); + if (!attribute.hasContext(1)) { + return null; + } String name = attribute.getContext(1); PosePart posePart = PosePart.fromName(name); if (posePart == null) { @@ -104,12 +106,9 @@ else if (attribute.startsWith("armor_pose") && attribute.hasContext(1)) { return null; } else { - return fromEulerAngle(posePart.getAngle((ArmorStand) entity.getBukkitEntity())) - .getObjectAttribute(attribute.fulfill(1)); + return fromEulerAngle(posePart.getAngle((ArmorStand) entity.entity.getBukkitEntity())); } - } - - return null; + }); } @Override @@ -118,31 +117,43 @@ public void adjust(Mechanism mechanism) { // <--[mechanism] // @object EntityTag // @name armor_pose - // @input ListTag + // @input MapTag // @description - // Sets the angle for various parts of the armor stand in the - // format: PART|ANGLE|... - // For example, head|4.5,3,4.5|body|5.4,3.2,1 + // Sets the angle for various parts of the armor stand. + // For example, head=4.5,3,4.5;body=5.4,3.2,1 // Valid parts: HEAD, BODY, LEFT_ARM, RIGHT_ARM, LEFT_LEG, RIGHT_LEG // Angles are in radians! // Here's a website to help you figure out the correct values: <@link url https://bgielinor.github.io/Minecraft-ArmorStand/>. // @tags - // - // ]> + // // --> if (mechanism.matches("armor_pose")) { ArmorStand armorStand = (ArmorStand) entity.getBukkitEntity(); - ListTag list = mechanism.valueAsType(ListTag.class); - Iterator iterator = list.iterator(); - while (iterator.hasNext()) { - String name = iterator.next(); - String angle = iterator.next(); - PosePart posePart = PosePart.fromName(name); - if (posePart == null) { - mechanism.echoError("Invalid pose part specified: " + name + "; ignoring next: " + angle); + if (mechanism.getValue().asString().contains("=")) { + MapTag map = mechanism.valueAsType(MapTag.class); + for (Map.Entry entry : map.map.entrySet()) { + PosePart posePart = PosePart.fromName(entry.getKey().str); + if (posePart == null) { + mechanism.echoError("Invalid pose part specified: " + entry.getKey().str); + } + else { + posePart.setAngle(armorStand, toEulerAngle(entry.getValue().asType(LocationTag.class, mechanism.context))); + } } - else { - posePart.setAngle(armorStand, toEulerAngle(LocationTag.valueOf(angle, mechanism.context))); + } + else { + ListTag list = mechanism.valueAsType(ListTag.class); + Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + String name = iterator.next(); + String angle = iterator.next(); + PosePart posePart = PosePart.fromName(name); + if (posePart == null) { + mechanism.echoError("Invalid pose part specified: " + name + "; ignoring next: " + angle); + } + else { + posePart.setAngle(armorStand, toEulerAngle(LocationTag.valueOf(angle, mechanism.context))); + } } } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemArmorPose.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemArmorPose.java new file mode 100644 index 0000000000..427f02c1db --- /dev/null +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemArmorPose.java @@ -0,0 +1,194 @@ +package com.denizenscript.denizen.objects.properties.item; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.util.jnbt.*; +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.core.MapTag; +import com.denizenscript.denizencore.objects.properties.Property; +import com.denizenscript.denizencore.objects.properties.PropertyParser; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class ItemArmorPose implements Property { + + public static boolean describes(ObjectTag item) { + return item instanceof ItemTag + && ((ItemTag) item).getBukkitMaterial() == Material.ARMOR_STAND; + } + + public static ItemArmorPose getFrom(ObjectTag item) { + if (!describes(item)) { + return null; + } + else { + return new ItemArmorPose((ItemTag) item); + } + } + + public static final String[] handledMechs = new String[] { + "armor_pose" + }; + + private ItemArmorPose(ItemTag item) { + this.item = item; + } + + public static void procPart(CompoundTag pose, String nmsName, String denizenName, MapTag result) { + List list = pose.getList(nmsName); + if (list == null || list.size() != 3) { + return; + } + Tag x = list.get(0), y = list.get(1), z = list.get(2); + if (!(x instanceof FloatTag) || !(y instanceof FloatTag) || !(z instanceof FloatTag)) { + return; + } + String combined = x.getValue() + "," + y.getValue() + "," + z.getValue(); + result.putObject(denizenName, new ElementTag(combined)); + } + + public MapTag getPoseMap() { + CompoundTag compoundTag = NMSHandler.getItemHelper().getNbtData(item.getItemStack()); + if (compoundTag == null) { + return null; + } + Tag entPart = compoundTag.getValue().get("EntityTag"); + if (!(entPart instanceof CompoundTag)) { + return null; + } + Tag posePart = ((CompoundTag) entPart).getValue().get("Pose"); + if (!(posePart instanceof CompoundTag)) { + return null; + } + CompoundTag pose = (CompoundTag) posePart; + MapTag result = new MapTag(); + procPart(pose, "Head", "head", result); + procPart(pose, "Body", "body", result); + procPart(pose, "LeftArm", "left_arm", result); + procPart(pose, "RightArm", "right_arm", result); + procPart(pose, "LeftLeg", "left_leg", result); + procPart(pose, "RightLeg", "right_leg", result); + return result; + } + + ItemTag item; + + public static void registerTags() { + + // <--[tag] + // @attribute + // @returns MapTag + // @group properties + // @mechanism ItemTag.armor_pose + // @description + // Returns the pose of this armor stand item, if any. + // Map has keys: head, body, left_arm, right_arm, left_leg, right_leg + // --> + PropertyParser.registerTag(MapTag.class, "armor_stand_data", (attribute, item) -> { + return item.getPoseMap(); + }); + } + + @Override + public String getPropertyString() { + MapTag result = getPoseMap(); + if (result == null) { + return null; + } + return result.toString(); + } + + @Override + public String getPropertyId() { + return "armor_pose"; + } + + public static void procMechKey(Mechanism mech, CompoundTagBuilder pose, String nmsName, String denizenName, MapTag input) { + ObjectTag value = input.getObject(denizenName); + if (value == null) { + return; + } + List raw = CoreUtilities.split(value.toString(), ','); + if (raw.size() != 3) { + mech.echoError("Invalid pose piece '" + value + "'"); + return; + } + List rawList = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + rawList.add(new FloatTag(Float.valueOf(raw.get(i)))); + } + JNBTListTag list = new JNBTListTag(FloatTag.class, rawList); + pose.put(nmsName, list); + } + + @Override + public void adjust(Mechanism mechanism) { + + // <--[mechanism] + // @object ItemTag + // @name armor_pose + // @input MapTag + // @description + // Sets the pose of this armor stand item. + // Allowed keys: head, body, left_arm, right_arm, left_leg, right_leg + // @tags + // + // --> + if (mechanism.matches("armor_pose")) { + CompoundTag compoundTag = NMSHandler.getItemHelper().getNbtData(item.getItemStack()); + Tag entPart, posePart; + if (mechanism.hasValue() && mechanism.requireObject(MapTag.class)) { + if (compoundTag == null) { + compoundTag = new CompoundTagBuilder().build(); + } + entPart = compoundTag.getValue().get("EntityTag"); + if (!(entPart instanceof CompoundTag)) { + entPart = new CompoundTagBuilder().build(); + } + CompoundTagBuilder poseBuilder = new CompoundTagBuilder(); + MapTag input = mechanism.valueAsType(MapTag.class); + procMechKey(mechanism, poseBuilder, "Head", "head", input); + procMechKey(mechanism, poseBuilder, "Body", "body", input); + procMechKey(mechanism, poseBuilder, "LeftArm", "left_arm", input); + procMechKey(mechanism, poseBuilder, "RightArm", "right_arm", input); + procMechKey(mechanism, poseBuilder, "LeftLeg", "left_leg", input); + procMechKey(mechanism, poseBuilder, "RightLeg", "right_leg", input); + CompoundTag pose = poseBuilder.build(); + if (pose.getValue().isEmpty()) { + entPart = ((CompoundTag) entPart).createBuilder().remove("Pose").build(); + } + else { + entPart = ((CompoundTag) entPart).createBuilder().put("Pose", pose).build(); + } + } + else { + if (compoundTag == null) { + return; + } + entPart = compoundTag.getValue().get("EntityTag"); + if (!(entPart instanceof CompoundTag)) { + return; + } + posePart = ((CompoundTag) entPart).getValue().get("Pose"); + if (!(posePart 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(); + } + ItemStack result = NMSHandler.getItemHelper().setNbtData(item.getItemStack(), compoundTag); + item.setItemStack(result); + } + } +} diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java index 56fc40d8c5..fe67dd1818 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java @@ -71,8 +71,7 @@ private ItemRawNBT(ItemTag _item) { "SkullOwner", // Firework specific "Explosion", "Fireworks", - // Armor stand specific - // "EntityTag", // Temporarily sent through as raw due to lack of API coverage + //"EntityTag", // Special handling // Bucket specific //"BucketVariantTag", // Temporarily sent through as raw due to lack of property coverage // Map specific @@ -104,6 +103,20 @@ public MapTag getNonDefaultNBTMap() { } } } + if (item.getBukkitMaterial() == Material.ARMOR_STAND) { + MapTag entityMap = (MapTag) result.getObject("EntityTag"); + if (entityMap != null) { + entityMap.putObject("Pose", null); + entityMap.putObject("Small", null); + entityMap.putObject("NoBasePlate", null); + entityMap.putObject("Marker", null); + entityMap.putObject("Invisible", null); + entityMap.putObject("ShowArms", null); + if (entityMap.map.isEmpty()) { + result.putObject("EntityTag", null); + } + } + } return result; }