diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/NPCTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/NPCTag.java index a99fa9ec70..c7c8d8e6f3 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/NPCTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/NPCTag.java @@ -501,7 +501,7 @@ public static void register() { // --> tagProcessor.registerTag(ElementTag.class, "nickname", (attribute, object) -> { return new ElementTag(object.getCitizen().hasTrait(NicknameTrait.class) ? object.getCitizen().getOrAddTrait(NicknameTrait.class) - .getNickname() : object.getName()); + .getNickname() : object.getName(), true); }); // Documented in EntityTag @@ -510,16 +510,16 @@ public static void register() { BukkitImplDeprecations.npcNicknameTag.warn(attribute.context); attribute.fulfill(1); return new ElementTag(object.getCitizen().hasTrait(NicknameTrait.class) ? object.getCitizen().getOrAddTrait(NicknameTrait.class) - .getNickname() : object.getName()); + .getNickname() : object.getName(), true); } - return new ElementTag(object.getName()); + return new ElementTag(object.getName(), true); }); // <--[tag] // @attribute // @returns ListTag // @description - // Returns a list of all of the NPC's traits. + // Returns a list of all the NPC's traits. // --> tagProcessor.registerTag(ListTag.class, "traits", (attribute, object) -> { List list = new ArrayList<>(); @@ -535,14 +535,9 @@ public static void register() { // @description // Returns whether the NPC has a specified trait. // --> - tagProcessor.registerTag(ElementTag.class, "has_trait", (attribute, object) -> { - if (attribute.hasParam()) { - Class trait = CitizensAPI.getTraitFactory().getTraitClass(attribute.getParam()); - if (trait != null) { - return new ElementTag(object.getCitizen().hasTrait(trait)); - } - } - return null; + tagProcessor.registerTag(ElementTag.class, ElementTag.class, "has_trait", (attribute, object, param) -> { + Class trait = CitizensAPI.getTraitFactory().getTraitClass(param.asString()); + return trait != null ? new ElementTag(object.getCitizen().hasTrait(trait)) : null; }); // <--[tag] @@ -561,15 +556,12 @@ public static void register() { // @description // Returns whether the NPC has a specified trigger. // --> - tagProcessor.registerTag(ElementTag.class, "has_trigger", (attribute, object) -> { - if (!attribute.hasParam()) { - return null; - } + tagProcessor.registerTag(ElementTag.class, ElementTag.class, "has_trigger", (attribute, object, param) -> { if (!object.getCitizen().hasTrait(TriggerTrait.class)) { return new ElementTag(false); } TriggerTrait trait = object.getCitizen().getOrAddTrait(TriggerTrait.class); - return new ElementTag(trait.hasTrigger(attribute.getParam())); + return new ElementTag(trait.hasTrigger(param.asString())); }); // <--[tag] @@ -579,7 +571,7 @@ public static void register() { // Returns whether the NPC has anchors assigned. // --> tagProcessor.registerTag(ElementTag.class, "has_anchors", (attribute, object) -> { - return (new ElementTag(object.getCitizen().getOrAddTrait(Anchors.class).getAnchors().size() > 0)); + return new ElementTag(!object.getCitizen().getOrAddTrait(Anchors.class).getAnchors().isEmpty()); }); // <--[tag] @@ -589,11 +581,7 @@ public static void register() { // Returns a list of anchor names currently assigned to the NPC. // --> tagProcessor.registerTag(ListTag.class, "list_anchors", (attribute, object) -> { - ListTag list = new ListTag(); - for (Anchor anchor : object.getCitizen().getOrAddTrait(Anchors.class).getAnchors()) { - list.add(anchor.getName()); - } - return list; + return new ListTag(object.getCitizen().getOrAddTrait(Anchors.class).getAnchors(), anchor -> new ElementTag(anchor.getName(), true)); }); // <--[tag] @@ -606,22 +594,18 @@ public static void register() { Anchors trait = object.getCitizen().getOrAddTrait(Anchors.class); if (attribute.hasParam()) { Anchor anchor = trait.getAnchor(attribute.getParam()); - if (anchor != null) { - return new LocationTag(anchor.getLocation()); - } - else { - attribute.echoError("NPC Anchor '" + attribute.getParam() + "' is not defined."); - return null; - } + if (anchor != null) { + return new LocationTag(anchor.getLocation()); + } + else { + attribute.echoError("NPC Anchor '" + attribute.getParam() + "' is not defined."); + return null; + } } else if (attribute.startsWith("list", 2)) { attribute.fulfill(1); BukkitImplDeprecations.npcAnchorListTag.warn(attribute.context); - ListTag list = new ListTag(); - for (Anchor anchor : trait.getAnchors()) { - list.add(anchor.getName()); - } - return list; + return new ListTag(trait.getAnchors(), anchor -> new ElementTag(anchor.getName(), true)); } else { attribute.echoError("npc.anchor[...] tag must have an input."); @@ -635,18 +619,14 @@ else if (attribute.startsWith("list", 2)) { // @description // Returns the specified constant from the NPC. // --> - tagProcessor.registerTag(ElementTag.class, "constant", (attribute, object) -> { - if (attribute.hasParam()) { - if (object.getCitizen().hasTrait(ConstantsTrait.class) - && object.getCitizen().getOrAddTrait(ConstantsTrait.class).getConstant(attribute.getParam()) != null) { - return new ElementTag(object.getCitizen().getOrAddTrait(ConstantsTrait.class) - .getConstant(attribute.getParam())); - } - else { - return null; - } + tagProcessor.registerTag(ElementTag.class, ElementTag.class, "constant", (attribute, object, param) -> { + if (object.getCitizen().hasTrait(ConstantsTrait.class) + && object.getCitizen().getOrAddTrait(ConstantsTrait.class).getConstant(param.asString()) != null) { + return new ElementTag(object.getCitizen().getOrAddTrait(ConstantsTrait.class).getConstant(param.asString()), true); + } + else { + return null; } - return null; }); // <--[tag] @@ -655,13 +635,8 @@ else if (attribute.startsWith("list", 2)) { // @description // Returns true if the NPC has the specified pose, otherwise returns false. // --> - tagProcessor.registerTag(ElementTag.class, "has_pose", (attribute, object) -> { - if (attribute.hasParam()) { - return new ElementTag(object.getCitizen().getOrAddTrait(Poses.class).hasPose(attribute.getParam())); - } - else { - return null; - } + tagProcessor.registerTag(ElementTag.class, ElementTag.class, "has_pose", (attribute, object, param) -> { + return new ElementTag(object.getCitizen().getOrAddTrait(Poses.class).hasPose(param.asString())); }); // <--[tag] @@ -671,14 +646,9 @@ else if (attribute.startsWith("list", 2)) { // Returns the pose as a LocationTag with x, y, and z set to 0, and the world set to the first // possible available world Bukkit knows about. // --> - tagProcessor.registerTag(LocationTag.class, "pose", (attribute, object) -> { - if (attribute.hasParam()) { - Pose pose = object.getCitizen().getOrAddTrait(Poses.class).getPose(attribute.getParam()); - return new LocationTag(org.bukkit.Bukkit.getWorlds().get(0), 0, 0, 0, pose.getYaw(), pose.getPitch()); - } - else { - return null; - } + tagProcessor.registerTag(LocationTag.class, ElementTag.class, "pose", (attribute, object, param) -> { + Pose pose = object.getCitizen().getOrAddTrait(Poses.class).getPose(param.asString()); + return new LocationTag(org.bukkit.Bukkit.getWorlds().get(0), 0, 0, 0, pose.getYaw(), pose.getPitch()); }, "get_pose"); // <--[tag] @@ -716,11 +686,7 @@ else if (attribute.startsWith("list", 2)) { if (stands == null || stands.isEmpty()) { return null; } - ListTag output = new ListTag(); - for (Entity stand : stands) { - output.addObject(new EntityTag(stand).getDenizenObject()); - } - return output; + return new ListTag(stands, stand -> new EntityTag(stand).getDenizenObject()); }); // <--[tag] @@ -865,7 +831,7 @@ else if (attribute.startsWith("list", 2)) { if (skin.getSignature() != null) { sign = ";" + skin.getSignature(); } - return new ElementTag(tex + sign); + return new ElementTag(tex + sign, true); } return null; }); @@ -883,7 +849,7 @@ else if (attribute.startsWith("list", 2)) { return null; } SkinTrait skin = object.getCitizen().getOrAddTrait(SkinTrait.class); - return new ElementTag(skin.getSkinName() + "|" + skin.getTexture()); + return new ElementTag(skin.getSkinName() + "|" + skin.getTexture(), true); }); // <--[tag] @@ -895,7 +861,7 @@ else if (attribute.startsWith("list", 2)) { // --> tagProcessor.registerTag(ElementTag.class, "skin", (attribute, object) -> { if (object.getCitizen().hasTrait(SkinTrait.class)) { - return new ElementTag(object.getCitizen().getOrAddTrait(SkinTrait.class).getSkinName()); + return new ElementTag(object.getCitizen().getOrAddTrait(SkinTrait.class).getSkinName(), true); } return null; }); @@ -1044,13 +1010,7 @@ else if (attribute.startsWith("list", 2)) { return null; } else { - ListTag result = new ListTag(); - for (AssignmentScriptContainer container : citizen.getOrAddTrait(AssignmentTrait.class).containerCache) { - if (container != null) { - result.addObject(new ScriptTag(container)); - } - } - return result; + return new ListTag(citizen.getOrAddTrait(AssignmentTrait.class).containerCache, Objects::nonNull, ScriptTag::new); } }); @@ -1139,7 +1099,7 @@ else if (attribute.startsWith("list", 2)) { // Not related to Sentinel combat. // --> tagProcessor.registerTag(ElementTag.class, "attack_strategy", (attribute, object) -> { - return new ElementTag(object.getNavigator().getLocalParameters().attackStrategy().toString()); + return new ElementTag(object.getNavigator().getLocalParameters().attackStrategy().toString(), true); }); // <--[tag] @@ -1224,7 +1184,7 @@ else if (attribute.startsWith("list", 2)) { if (object.getNavigator().getTargetType() == null) { return null; } - return new ElementTag(object.getNavigator().getTargetType().toString()); + return new ElementTag(object.getNavigator().getTargetType().toString(), true); }); // <--[tag] @@ -1247,7 +1207,7 @@ else if (attribute.startsWith("list", 2)) { // Returns the name of the registry this NPC came from. // --> tagProcessor.registerTag(ElementTag.class, "registry_name", (attribute, object) -> { - return new ElementTag(object.getCitizen().getOwningRegistry().getName()); + return new ElementTag(object.getCitizen().getOwningRegistry().getName(), true); }); // <--[tag] @@ -1256,15 +1216,9 @@ else if (attribute.startsWith("list", 2)) { // @description // Returns the value of a Citizens NPC metadata key. // --> - tagProcessor.registerTag(ElementTag.class, "citizens_data", (attribute, object) -> { - if (!attribute.hasParam()) { - return null; - } - Object val = object.getCitizen().data().get(attribute.getParam()); - if (val == null) { - return null; - } - return new ElementTag(val.toString()); + tagProcessor.registerTag(ElementTag.class, ElementTag.class, "citizens_data", (attribute, object, param) -> { + Object val = object.getCitizen().data().get(param.asString()); + return val != null ? new ElementTag(val.toString(), true) : null; }); // <--[tag] @@ -1343,6 +1297,16 @@ else if (attribute.startsWith("list", 2)) { return null; }); + // <--[tag] + // @attribute ]> + // @returns ElementTag(Boolean) + // @description + // Returns whether an NPC can navigate to a specified location. + // --> + tagProcessor.registerTag(ElementTag.class, LocationTag.class, "can_navigate_to", (attribute, object, param) -> { + return new ElementTag(object.npc.getNavigator().canNavigateTo(param)); + }); + // <--[mechanism] // @object NPCTag // @name hologram_lines @@ -1420,15 +1384,14 @@ else if (attribute.startsWith("list", 2)) { // // --> tagProcessor.registerMechanism("wander_xrange", false, ElementTag.class, (object, mechanism, input) -> { - if (!mechanism.requireInteger()) { - return; - } - Waypoints wp = object.getCitizen().getOrAddTrait(Waypoints.class); - if (wp.getCurrentProvider() instanceof WanderWaypointProvider wanderWaypointProvider) { - wanderWaypointProvider.setXYRange(input.asInt(), wanderWaypointProvider.getYRange()); - } - else { - mechanism.echoError("Must set waypoint_provider to 'wander' before setting wander_xrange!"); + if (mechanism.requireInteger()) { + Waypoints wp = object.getCitizen().getOrAddTrait(Waypoints.class); + if (wp.getCurrentProvider() instanceof WanderWaypointProvider wanderWaypointProvider) { + wanderWaypointProvider.setXYRange(input.asInt(), wanderWaypointProvider.getYRange()); + } + else { + mechanism.echoError("Must set waypoint_provider to 'wander' before setting wander_xrange!"); + } } }); @@ -1443,40 +1406,16 @@ else if (attribute.startsWith("list", 2)) { // // --> tagProcessor.registerMechanism("wander_yrange", false, ElementTag.class, (object, mechanism, input) -> { - if (!mechanism.requireInteger()) { - return; - } - Waypoints wp = object.getCitizen().getOrAddTrait(Waypoints.class); - if (wp.getCurrentProvider() instanceof WanderWaypointProvider wanderWaypointProvider) { - wanderWaypointProvider.setXYRange(wanderWaypointProvider.getXRange(), input.asInt()); - } - else { - mechanism.echoError("Must set waypoint_provider to 'wander' before setting wander_yrange!"); + if (mechanism.requireInteger()) { + Waypoints wp = object.getCitizen().getOrAddTrait(Waypoints.class); + if (wp.getCurrentProvider() instanceof WanderWaypointProvider wanderWaypointProvider) { + wanderWaypointProvider.setXYRange(wanderWaypointProvider.getXRange(), input.asInt()); + } + else { + mechanism.echoError("Must set waypoint_provider to 'wander' before setting wander_yrange!"); + } } }); - } - - public static ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); - - @Override - public ObjectTag getObjectAttribute(Attribute attribute) { - return tagProcessor.getObjectAttribute(this, attribute); - } - - @Override - public ObjectTag getNextObjectTypeDown() { - if (getEntity() != null) { - return new EntityTag(this); - } - return new ElementTag(identify()); - } - - public void applyProperty(Mechanism mechanism) { - mechanism.echoError("Cannot apply properties to an NPC!"); - } - - @Override - public void adjust(Mechanism mechanism) { // TODO: For all the mechanism tags, add the @Mechanism link! @@ -1489,11 +1428,11 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("set_assignment") && mechanism.requireObject(ScriptTag.class)) { - AssignmentTrait trait = getCitizen().getOrAddTrait(AssignmentTrait.class); + tagProcessor.registerMechanism("set_assignment", false, ScriptTag.class, (object, mechanism, input) -> { + AssignmentTrait trait = object.getCitizen().getOrAddTrait(AssignmentTrait.class); trait.clearAssignments(null); - trait.addAssignmentScript((AssignmentScriptContainer) mechanism.valueAsType(ScriptTag.class).getContainer(), null); - } + trait.addAssignmentScript((AssignmentScriptContainer) input.getContainer(), null); + }); // <--[mechanism] // @object NPCTag @@ -1504,9 +1443,9 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("add_assignment") && mechanism.requireObject(ScriptTag.class)) { - getCitizen().getOrAddTrait(AssignmentTrait.class).addAssignmentScript((AssignmentScriptContainer) mechanism.valueAsType(ScriptTag.class).getContainer(), null); - } + tagProcessor.registerMechanism("add_assignment", false, ScriptTag.class, (object, mechanism, input) -> { + object.getCitizen().getOrAddTrait(AssignmentTrait.class).addAssignmentScript((AssignmentScriptContainer) input.getContainer(), null); + }); // <--[mechanism] // @object NPCTag @@ -1517,20 +1456,21 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("remove_assignment")) { - if (npc.hasTrait(AssignmentTrait.class)) { - if (mechanism.hasValue()) { - AssignmentTrait trait = getCitizen().getOrAddTrait(AssignmentTrait.class); - trait.removeAssignmentScript(mechanism.getValue().asString(), null); - trait.checkAutoRemove(); - } - else { - BukkitImplDeprecations.assignmentRemove.warn(mechanism.context); - getCitizen().getOrAddTrait(AssignmentTrait.class).clearAssignments(null); - npc.removeTrait(AssignmentTrait.class); - } + tagProcessor.registerMechanism("remove_assignment", false, (object, mechanism) -> { + if (!object.npc.hasTrait(AssignmentTrait.class)) { + mechanism.echoError("The npc used in the 'NPCTag.remove_assignment' mechanism does not have any assignments."); } - } + else if (mechanism.hasValue()) { + AssignmentTrait trait = object.getCitizen().getOrAddTrait(AssignmentTrait.class); + trait.removeAssignmentScript(mechanism.getValue().asString(), null); + trait.checkAutoRemove(); + } + else { + BukkitImplDeprecations.assignmentRemove.warn(mechanism.context); + object.getCitizen().getOrAddTrait(AssignmentTrait.class).clearAssignments(null); + object.npc.removeTrait(AssignmentTrait.class); + } + }); // <--[mechanism] // @object NPCTag @@ -1541,12 +1481,15 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("clear_assignments")) { - if (npc.hasTrait(AssignmentTrait.class)) { - getCitizen().getOrAddTrait(AssignmentTrait.class).clearAssignments(null); - npc.removeTrait(AssignmentTrait.class); + tagProcessor.registerMechanism("clear_assignments", false, (object, mechanism) -> { + if (object.npc.hasTrait(AssignmentTrait.class)) { + object.getCitizen().getOrAddTrait(AssignmentTrait.class).clearAssignments(null); + object.npc.removeTrait(AssignmentTrait.class); } - } + else { + mechanism.echoError("The npc used in the 'NPCTag.clear_assignments' mechanism did not have any assignments."); + } + }); // <--[mechanism] // @object NPCTag @@ -1558,11 +1501,13 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("hologram_direction")) { // && mechanism.requireEnum(HologramTrait.HologramDirection.class) + tagProcessor.registerMechanism("hologram_direction", false, ElementTag.class, (object, mechanism, param) -> { + //if (mechanism.requireEnum(HologramTrait.HologramDirection.class)) { + //HologramTrait hologram = object.getCitizen().getOrAddTrait(HologramTrait.class); + //hologram.setDirection(HologramTrait.HologramDirection.valueOf(param.asString().toUpperCase())); + //} BukkitImplDeprecations.npcHologramDirection.warn(mechanism.context); - //HologramTrait hologram = getCitizen().getOrAddTrait(HologramTrait.class); - //hologram.setDirection(HologramTrait.HologramDirection.valueOf(mechanism.getValue().asString().toUpperCase())); - } + }); // <--[mechanism] // @object NPCTag @@ -1573,10 +1518,12 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("hologram_line_height") && mechanism.requireDouble()) { - HologramTrait hologram = getCitizen().getOrAddTrait(HologramTrait.class); - hologram.setLineHeight(mechanism.getValue().asDouble()); - } + tagProcessor.registerMechanism("hologram_line_height", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireDouble()) { + HologramTrait hologram = object.getCitizen().getOrAddTrait(HologramTrait.class); + hologram.setLineHeight(input.asDouble()); + } + }); // <--[mechanism] // @object NPCTag @@ -1587,9 +1534,14 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("set_nickname")) { - getNicknameTrait().setNickname(mechanism.getValue().asString()); - } + tagProcessor.registerMechanism("set_nickname", false, (object, mechanism) -> { + if (mechanism.hasValue()) { + object.getNicknameTrait().setNickname(mechanism.getValue().asString()); + } + else { + object.getNicknameTrait().removeNickname(); + } + }); // <--[mechanism] // @object NPCTag @@ -1600,9 +1552,9 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("remove_nickname")) { - getNicknameTrait().removeNickname(); - } + tagProcessor.registerMechanism("remove_nickname", false, (object, mechanism) -> { + object.getNicknameTrait().removeNickname(); + }); // <--[mechanism] // @object NPCTag @@ -1613,9 +1565,9 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("set_entity_type") && mechanism.requireObject(EntityTag.class)) { - getCitizen().setBukkitEntityType(mechanism.valueAsType(EntityTag.class).getBukkitEntityType()); - } + tagProcessor.registerMechanism("set_entity_type", false, EntityTag.class, (object, mechanism, input) -> { + object.getCitizen().setBukkitEntityType(input.getBukkitEntityType()); + }); // <--[mechanism] // @object NPCTag @@ -1626,9 +1578,9 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("name") || mechanism.matches("set_name")) { - getCitizen().setName(mechanism.getValue().asString().length() > 256 ? mechanism.getValue().asString().substring(0, 256) : mechanism.getValue().asString()); - } + tagProcessor.registerMechanism("name", false, ElementTag.class, (object, mechanism, input) -> { + object.getCitizen().setName(input.asString().length() > 256 ? input.asString().substring(0, 256) : input.asString()); + }, "set_name"); // <--[mechanism] // @object NPCTag @@ -1639,14 +1591,9 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("owner")) { - if (PlayerTag.matches(mechanism.getValue().asString())) { - getCitizen().getOrAddTrait(Owner.class).setOwner(mechanism.valueAsType(PlayerTag.class).getPlayerEntity()); - } - else { - getCitizen().getOrAddTrait(Owner.class).setOwner(mechanism.getValue().asString()); - } - } + tagProcessor.registerMechanism("owner", false, PlayerTag.class, (object, mechanism, input) -> { + object.getCitizen().getOrAddTrait(Owner.class).setOwner(input.getPlayerEntity()); + }); // <--[mechanism] // @object NPCTag @@ -1659,29 +1606,29 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("skin_blob")) { + tagProcessor.registerMechanism("skin_blob", false, (object, mechanism) -> { if (!mechanism.hasValue()) { - if (getCitizen().hasTrait(SkinTrait.class)) { - getCitizen().getOrAddTrait(SkinTrait.class).clearTexture(); - if (getCitizen().isSpawned()) { - getCitizen().despawn(DespawnReason.PENDING_RESPAWN); - getCitizen().spawn(getCitizen().getStoredLocation()); + if (object.getCitizen().hasTrait(SkinTrait.class)) { + object.getCitizen().getOrAddTrait(SkinTrait.class).clearTexture(); + if (object.getCitizen().isSpawned()) { + object.getCitizen().despawn(DespawnReason.PENDING_RESPAWN); + object.getCitizen().spawn(object.getCitizen().getStoredLocation()); } } } else { - SkinTrait skinTrait = getCitizen().getOrAddTrait(SkinTrait.class); + SkinTrait skinTrait = object.getCitizen().getOrAddTrait(SkinTrait.class); String[] dat = mechanism.getValue().asString().split(";"); if (dat.length < 2) { Debug.echoError("Invalid skin_blob input. Must specify texture;signature;name in full."); return; } skinTrait.setSkinPersistent(dat.length > 2 ? dat[2] : UUID.randomUUID().toString(), dat[1], dat[0]); - if (getCitizen().isSpawned() && getCitizen().getEntity() instanceof SkinnableEntity) { - ((SkinnableEntity) getCitizen().getEntity()).getSkinTracker().notifySkinChange(true); + if (object.getCitizen().isSpawned() && object.getCitizen().getEntity() instanceof SkinnableEntity skinnable) { + skinnable.getSkinTracker().notifySkinChange(true); } } - } + }); // <--[mechanism] // @object NPCTag @@ -1694,21 +1641,21 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("skin")) { + tagProcessor.registerMechanism("skin", false, (object, mechanism) -> { if (!mechanism.hasValue()) { - if (getCitizen().hasTrait(SkinTrait.class)) { - getCitizen().getOrAddTrait(SkinTrait.class).clearTexture(); + if (object.getCitizen().hasTrait(SkinTrait.class)) { + object.getCitizen().getOrAddTrait(SkinTrait.class).clearTexture(); } } else { - SkinTrait skinTrait = getCitizen().getOrAddTrait(SkinTrait.class); + SkinTrait skinTrait = object.getCitizen().getOrAddTrait(SkinTrait.class); skinTrait.setSkinName(mechanism.getValue().asString()); } - if (getCitizen().isSpawned()) { - getCitizen().despawn(DespawnReason.PENDING_RESPAWN); - getCitizen().spawn(getCitizen().getStoredLocation()); + if (object.getCitizen().isSpawned()) { + object.getCitizen().despawn(DespawnReason.PENDING_RESPAWN); + object.getCitizen().spawn(object.getCitizen().getStoredLocation()); } - } + }); // <--[mechanism] // @object NPCTag @@ -1720,9 +1667,11 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("auto_update_skin") && mechanism.requireBoolean()) { - getCitizen().getOrAddTrait(SkinTrait.class).setShouldUpdateSkins(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("auto_update_skin", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getCitizen().getOrAddTrait(SkinTrait.class).setShouldUpdateSkins(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1731,10 +1680,10 @@ public void adjust(Mechanism mechanism) { // @description // Sets the item type of the item. // --> - if (mechanism.matches("item_type") && mechanism.requireObject(ItemTag.class)) { - ItemTag item = mechanism.valueAsType(ItemTag.class); - Material mat = item.getMaterial().getMaterial(); - Entity npcEntity = getEntity(); + tagProcessor.registerMechanism("item_type", false, ItemTag.class, (object, mechanism, input) -> { + Material mat = input.getMaterial().getMaterial(); + Entity npcEntity = object.getEntity(); + NPC citizen = object.getCitizen(); if (npcEntity instanceof Item droppedItem) { droppedItem.getItemStack().setType(mat); } @@ -1742,27 +1691,27 @@ else if (npcEntity instanceof ItemFrame itemFrame) { itemFrame.getItem().setType(mat); } else if (npcEntity instanceof FallingBlock) { - getCitizen().data().setPersistent(NPC.Metadata.ITEM_ID, mat.name()); - getCitizen().data().setPersistent(NPC.Metadata.ITEM_DATA, 0); + citizen.data().setPersistent(NPC.Metadata.ITEM_ID, mat.name()); + citizen.data().setPersistent(NPC.Metadata.ITEM_DATA, 0); } else { Debug.echoError("NPC is the not an item type!"); } - if (getCitizen().isSpawned()) { - getCitizen().despawn(); - getCitizen().spawn(getCitizen().getStoredLocation()); + if (citizen.isSpawned()) { + citizen.despawn(); + citizen.spawn(citizen.getStoredLocation()); } - } + }); - if (mechanism.matches("spawn")) { + tagProcessor.registerMechanism("spawn", false, (object, mechanism) -> { BukkitImplDeprecations.npcSpawnMechanism.warn(mechanism.context); if (mechanism.requireObject("Invalid LocationTag specified. Assuming last known NPC location.", LocationTag.class)) { - getCitizen().spawn(mechanism.valueAsType(LocationTag.class)); + object.getCitizen().spawn(mechanism.valueAsType(LocationTag.class)); } else { - getCitizen().spawn(getCitizen().getStoredLocation()); + object.getCitizen().spawn(object.getCitizen().getStoredLocation()); } - } + }); // <--[mechanism] // @object NPCTag @@ -1773,10 +1722,12 @@ else if (npcEntity instanceof FallingBlock) { // @tags // // --> - if (mechanism.matches("range") && mechanism.requireFloat()) { - getCitizen().getNavigator().getDefaultParameters().range(mechanism.getValue().asFloat()); - getCitizen().getNavigator().getLocalParameters().range(mechanism.getValue().asFloat()); - } + tagProcessor.registerMechanism("range", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireFloat()) { + object.getCitizen().getNavigator().getDefaultParameters().range(input.asFloat()); + object.getCitizen().getNavigator().getLocalParameters().range(input.asFloat()); + } + }); // <--[mechanism] // @object NPCTag @@ -1787,10 +1738,12 @@ else if (npcEntity instanceof FallingBlock) { // @tags // // --> - if (mechanism.matches("attack_range") && mechanism.requireFloat()) { - getCitizen().getNavigator().getDefaultParameters().attackRange(mechanism.getValue().asFloat()); - getCitizen().getNavigator().getLocalParameters().attackRange(mechanism.getValue().asFloat()); - } + tagProcessor.registerMechanism("attack_range", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireFloat()) { + object.getCitizen().getNavigator().getDefaultParameters().attackRange(input.asFloat()); + object.getCitizen().getNavigator().getLocalParameters().attackRange(input.asFloat()); + } + }); // <--[mechanism] // @object NPCTag @@ -1801,15 +1754,17 @@ else if (npcEntity instanceof FallingBlock) { // @tags // // --> - if (mechanism.matches("speed") && mechanism.requireFloat()) { - getCitizen().getNavigator().getDefaultParameters().speedModifier(mechanism.getValue().asFloat()); - getCitizen().getNavigator().getLocalParameters().speedModifier(mechanism.getValue().asFloat()); - } + tagProcessor.registerMechanism("speed", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireFloat()) { + object.getCitizen().getNavigator().getDefaultParameters().speedModifier(input.asFloat()); + object.getCitizen().getNavigator().getLocalParameters().speedModifier(input.asFloat()); + } + }); - if (mechanism.matches("despawn")) { + tagProcessor.registerMechanism("despawn", false, (object, mechanism) -> { BukkitImplDeprecations.npcDespawnMech.warn(mechanism.context); - getCitizen().despawn(DespawnReason.PLUGIN); - } + object.getCitizen().despawn(DespawnReason.PLUGIN); + }); // <--[mechanism] // @object NPCTag @@ -1820,18 +1775,20 @@ else if (npcEntity instanceof FallingBlock) { // @tags // // --> - if (mechanism.matches("set_sneaking") && mechanism.requireBoolean()) { - if (!getCitizen().hasTrait(SneakingTrait.class)) { - getCitizen().addTrait(SneakingTrait.class); - } - SneakingTrait trait = getCitizen().getOrAddTrait(SneakingTrait.class); - if (trait.isSneaking() && !mechanism.getValue().asBoolean()) { - trait.stand(); - } - else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { - trait.sneak(); + tagProcessor.registerMechanism("set_sneaking", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + if (!object.getCitizen().hasTrait(SneakingTrait.class)) { + object.getCitizen().addTrait(SneakingTrait.class); + } + SneakingTrait trait = object.getCitizen().getOrAddTrait(SneakingTrait.class); + if (trait.isSneaking() && !mechanism.getValue().asBoolean()) { + trait.stand(); + } + else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { + trait.sneak(); + } } - } + }); // <--[mechanism] // @object NPCTag @@ -1842,9 +1799,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("set_protected") && mechanism.requireBoolean()) { - getCitizen().setProtected(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("set_protected", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getCitizen().setProtected(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1855,9 +1814,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("lookclose") && mechanism.requireBoolean()) { - getLookCloseTrait().lookClose(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("lookclose", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getLookCloseTrait().lookClose(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1868,9 +1829,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("controllable") && mechanism.requireBoolean()) { - getCitizen().getOrAddTrait(Controllable.class).setEnabled(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("controllable", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getCitizen().getOrAddTrait(Controllable.class).setEnabled(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1881,9 +1844,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("targetable") && mechanism.requireBoolean()) { - getCitizen().getOrAddTrait(TargetableTrait.class).setTargetable(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("targetable", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getCitizen().getOrAddTrait(TargetableTrait.class).setTargetable(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1894,14 +1859,16 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("teleport_on_stuck") && mechanism.requireBoolean()) { - if (mechanism.getValue().asBoolean()) { - getNavigator().getDefaultParameters().stuckAction(TeleportStuckAction.INSTANCE); - } - else { - getNavigator().getDefaultParameters().stuckAction(null); + tagProcessor.registerMechanism("teleport_on_stuck", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + if (input.asBoolean()) { + object.getNavigator().getDefaultParameters().stuckAction(TeleportStuckAction.INSTANCE); + } + else { + object.getNavigator().getDefaultParameters().stuckAction(null); + } } - } + }); // <--[mechanism] // @object NPCTag @@ -1912,10 +1879,12 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if ((mechanism.matches("distance_margin") || mechanism.matches("set_distance")) && mechanism.requireDouble()) { - getNavigator().getDefaultParameters().distanceMargin(mechanism.getValue().asDouble()); - getNavigator().getLocalParameters().distanceMargin(mechanism.getValue().asDouble()); - } + tagProcessor.registerMechanism("distance_margin", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireDouble()) { + object.getNavigator().getDefaultParameters().distanceMargin(input.asDouble()); + object.getNavigator().getLocalParameters().distanceMargin(input.asDouble()); + } + }, "set_distance"); // <--[mechanism] // @object NPCTag @@ -1926,10 +1895,12 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("path_distance_margin") && mechanism.requireDouble()) { - getNavigator().getDefaultParameters().pathDistanceMargin(mechanism.getValue().asDouble()); - getNavigator().getLocalParameters().pathDistanceMargin(mechanism.getValue().asDouble()); - } + tagProcessor.registerMechanism("path_distance_margin", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireDouble()) { + object.getNavigator().getDefaultParameters().pathDistanceMargin(input.asDouble()); + object.getNavigator().getLocalParameters().pathDistanceMargin(input.asDouble()); + } + }); // <--[mechanism] // @object NPCTag @@ -1941,9 +1912,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("use_new_finder") && mechanism.requireBoolean()) { - getNavigator().getDefaultParameters().useNewPathfinder(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("use_new_finder", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getNavigator().getDefaultParameters().useNewPathfinder(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1956,15 +1929,14 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("navigator_look_at")) { + tagProcessor.registerMechanism("navigator_look_at", false, (object, mechanism) -> { if (mechanism.hasValue() && mechanism.requireObject(LocationTag.class)) { - final LocationTag loc = mechanism.valueAsType(LocationTag.class); - getNavigator().getLocalParameters().lookAtFunction((n) -> loc); + object.getNavigator().getLocalParameters().lookAtFunction((n) -> mechanism.valueAsType(LocationTag.class)); } else { - getNavigator().getLocalParameters().lookAtFunction(null); + object.getNavigator().getLocalParameters().lookAtFunction(null); } - } + }); // <--[mechanism] // @object NPCTag @@ -1975,9 +1947,9 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // TODO // --> - if (mechanism.matches("name_visible")) { - getCitizen().data().setPersistent(NPC.Metadata.NAMEPLATE_VISIBLE, mechanism.getValue().asString()); - } + tagProcessor.registerMechanism("name_visible", false, ElementTag.class, (object, mechanism, input) -> { + object.getCitizen().data().setPersistent(NPC.Metadata.NAMEPLATE_VISIBLE, input.asString()); + }); // <--[mechanism] // @object NPCTag @@ -1988,9 +1960,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // TODO // --> - if (mechanism.matches("glow_color") && mechanism.requireEnum(ChatColor.class)) { - getCitizen().getOrAddTrait(ScoreboardTrait.class).setColor(ChatColor.valueOf(mechanism.getValue().asString().toUpperCase())); - } + tagProcessor.registerMechanism("glow_color", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireEnum(ChatColor.class)) { + object.getCitizen().getOrAddTrait(ScoreboardTrait.class).setColor(input.asEnum(ChatColor.class)); + } + }); // <--[mechanism] // @object NPCTag @@ -2001,19 +1975,18 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // TODO // --> - if (mechanism.matches("clear_waypoints")) { - Waypoints wp = getCitizen().getOrAddTrait(Waypoints.class); - if ((wp.getCurrentProvider() instanceof WaypointProvider.EnumerableWaypointProvider)) { - ((List) ((WaypointProvider.EnumerableWaypointProvider) wp.getCurrentProvider()).waypoints()).clear(); + tagProcessor.registerMechanism("clear_waypoints", false, (object, mechanism) -> { + Waypoints wp = object.getCitizen().getOrAddTrait(Waypoints.class); + if (wp.getCurrentProvider() instanceof WaypointProvider.EnumerableWaypointProvider provider) { + ((List) provider.waypoints()).clear(); } - else if ((wp.getCurrentProvider() instanceof WanderWaypointProvider)) { - List locs = ((WanderWaypointProvider) wp.getCurrentProvider()).getRegionCentres(); + else if (wp.getCurrentProvider() instanceof WanderWaypointProvider provider) { + List locs = provider.getRegionCentres(); for (Location loc : locs) { locs.remove(loc); // Manual clear to ensure recalculation for the forwarding list } - } - } + }); // <--[mechanism] // @object NPCTag @@ -2024,22 +1997,39 @@ else if ((wp.getCurrentProvider() instanceof WanderWaypointProvider)) { // @tags // TODO // --> - if (mechanism.matches("add_waypoint") && mechanism.requireObject(LocationTag.class)) { - Location target = mechanism.valueAsType(LocationTag.class).clone(); - Waypoints wp = getCitizen().getOrAddTrait(Waypoints.class); - if ((wp.getCurrentProvider() instanceof LinearWaypointProvider)) { - ((LinearWaypointProvider) wp.getCurrentProvider()).addWaypoint(new Waypoint(target)); + tagProcessor.registerMechanism("add_waypoint", false, LocationTag.class, (object, mechanism, input) -> { + Waypoints wp = object.getCitizen().getOrAddTrait(Waypoints.class); + if (wp.getCurrentProvider() instanceof LinearWaypointProvider provider) { + provider.addWaypoint(new Waypoint(input)); } - else if ((wp.getCurrentProvider() instanceof WaypointProvider.EnumerableWaypointProvider)) { - ((List) ((WaypointProvider.EnumerableWaypointProvider) wp.getCurrentProvider()).waypoints()).add(new Waypoint(target)); + else if (wp.getCurrentProvider() instanceof WaypointProvider.EnumerableWaypointProvider provider) { + ((List) provider.waypoints()).add(new Waypoint(input)); } - else if ((wp.getCurrentProvider() instanceof WanderWaypointProvider)) { - ((WanderWaypointProvider) wp.getCurrentProvider()).getRegionCentres().add(target); + else if (wp.getCurrentProvider() instanceof WanderWaypointProvider provider) { + provider.getRegionCentres().add(input); } - } + }); + } - tagProcessor.processMechanism(this, mechanism); + public static ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); + + @Override + public ObjectTag getObjectAttribute(Attribute attribute) { + return tagProcessor.getObjectAttribute(this, attribute); + } + @Override + public ObjectTag getNextObjectTypeDown() { + return getEntity() != null ? new EntityTag(this) : new ElementTag(identify()); + } + + public void applyProperty(Mechanism mechanism) { + mechanism.echoError("Cannot apply properties to an NPC!"); + } + + @Override + public void adjust(Mechanism mechanism) { + tagProcessor.processMechanism(this, mechanism); // Pass along to EntityTag mechanism handler if not already handled. if (!mechanism.fulfilled()) { if (isSpawned()) {