From 9691c90ffc1813010b2e5479ea5af293248b6fa9 Mon Sep 17 00:00:00 2001 From: Kam Date: Fri, 14 Mar 2025 05:35:23 -0400 Subject: [PATCH] Scripting for Attribute Handling on Players, Items, Totals, etc --- src/api | 2 +- .../npcs/controllers/AttributeController.java | 26 +++- .../data/attribute/AttributeDefinition.java | 4 +- .../data/attribute/ICustomAttribute.java | 12 -- .../data/attribute/PlayerAttribute.java | 15 +- .../data/attribute/PlayerAttributeMap.java | 14 +- .../requirement/IRequirementChecker.java | 2 + .../types/QuestActiveRequirement.java | 8 ++ .../types/QuestCompletedRequirement.java | 8 ++ .../tracker/PlayerAttributeTracker.java | 54 +++++-- .../java/noppes/npcs/scripted/NpcAPI.java | 5 + .../npcs/scripted/entity/ScriptPlayer.java | 3 + .../npcs/scripted/item/ScriptItemStack.java | 135 +++++++++++++++++- 13 files changed, 242 insertions(+), 46 deletions(-) delete mode 100644 src/main/java/kamkeel/npcs/controllers/data/attribute/ICustomAttribute.java diff --git a/src/api b/src/api index c7a74a3e0..dfa15687d 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit c7a74a3e0e4b979c880383737cd7d21d4b36d131 +Subproject commit dfa15687d0ab3cf2c544824b83d5b70338fad510 diff --git a/src/main/java/kamkeel/npcs/controllers/AttributeController.java b/src/main/java/kamkeel/npcs/controllers/AttributeController.java index 6eb28b513..3acb92cf5 100644 --- a/src/main/java/kamkeel/npcs/controllers/AttributeController.java +++ b/src/main/java/kamkeel/npcs/controllers/AttributeController.java @@ -5,6 +5,10 @@ import kamkeel.npcs.controllers.data.attribute.AttributeDefinition; import kamkeel.npcs.controllers.data.attribute.AttributeValueType; import kamkeel.npcs.controllers.data.attribute.tracker.PlayerAttributeTracker; import net.minecraft.entity.player.EntityPlayer; +import noppes.npcs.api.entity.IPlayer; +import noppes.npcs.api.handler.IAttributeHandler; +import noppes.npcs.api.handler.data.IAttributeDefinition; +import noppes.npcs.api.handler.data.IPlayerAttributes; import java.util.Collection; import java.util.HashMap; @@ -15,9 +19,9 @@ import java.util.UUID; * AttributeController is the central registry for attribute definitions. * It ensures that keys are unique. */ -public class AttributeController { +public class AttributeController implements IAttributeHandler { - public AttributeController Instance; + public static AttributeController Instance; public CustomAttributes attributes; // Tracking Player Attributes @@ -25,7 +29,7 @@ public class AttributeController { private static final Map definitions = new HashMap<>(); public AttributeController() { - this.Instance = this; + Instance = this; definitions.clear(); trackers.clear(); attributes = new CustomAttributes(); @@ -75,4 +79,20 @@ public class AttributeController { tracker.updateIfChanged(player); } } + + public IPlayerAttributes getPlayerAttributes(IPlayer player) { + if(player == null || player.getMCEntity() == null) + return null; + + EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity(); + return trackers.computeIfAbsent(entityPlayer.getUniqueID(), id -> new PlayerAttributeTracker(id)); + } + + public IAttributeDefinition getAttributeDefinition(String key) { + return definitions.get(key); + } + + public IAttributeDefinition[] getAllAttributesArray() { + return definitions.values().toArray(new AttributeDefinition[definitions.size()]); + } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/AttributeDefinition.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/AttributeDefinition.java index 8987c9aa3..d4151fef4 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/AttributeDefinition.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/AttributeDefinition.java @@ -1,6 +1,8 @@ package kamkeel.npcs.controllers.data.attribute; -public class AttributeDefinition { +import noppes.npcs.api.handler.data.IAttributeDefinition; + +public class AttributeDefinition implements IAttributeDefinition { private final String key; private String translationKey;// e.g., "main_attack_flat" private final String displayName; // Human‑readable name diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/ICustomAttribute.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/ICustomAttribute.java deleted file mode 100644 index 46b9ec2bc..000000000 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/ICustomAttribute.java +++ /dev/null @@ -1,12 +0,0 @@ -package kamkeel.npcs.controllers.data.attribute; - -/** - * IAttributeInstance represents an instance of an attribute (with a base value and applied modifiers). - */ -public interface ICustomAttribute { - AttributeDefinition getAttribute(); - - float getValue(); - - void setValue(float value); -} diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/PlayerAttribute.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/PlayerAttribute.java index dcd918225..4361a8fc9 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/PlayerAttribute.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/PlayerAttribute.java @@ -1,13 +1,15 @@ package kamkeel.npcs.controllers.data.attribute; +import noppes.npcs.api.handler.data.ICustomAttribute; + public class PlayerAttribute implements ICustomAttribute { private final AttributeDefinition attribute; - private float baseValue; + public float value; - public PlayerAttribute(AttributeDefinition attribute, float baseValue) { + public PlayerAttribute(AttributeDefinition attribute, float value) { this.attribute = attribute; - this.baseValue = baseValue; + this.value = value; } @Override @@ -17,11 +19,6 @@ public class PlayerAttribute implements ICustomAttribute { @Override public float getValue() { - return baseValue; - } - - @Override - public void setValue(float value) { - this.baseValue = value; + return value; } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/PlayerAttributeMap.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/PlayerAttributeMap.java index b489cf192..6889c5c10 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/PlayerAttributeMap.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/PlayerAttributeMap.java @@ -1,5 +1,7 @@ package kamkeel.npcs.controllers.data.attribute; +import noppes.npcs.api.handler.data.ICustomAttribute; + import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -8,22 +10,18 @@ import java.util.Map; * CustomAttributeMap holds a set of attribute instances for an entity (or item). */ public class PlayerAttributeMap { - private final Map map = new HashMap<>(); + public final Map map = new HashMap<>(); - public ICustomAttribute registerAttribute(AttributeDefinition attribute, float baseValue) { + public PlayerAttribute registerAttribute(AttributeDefinition attribute, float baseValue) { if (map.containsKey(attribute)) { throw new IllegalArgumentException("Attribute already registered: " + attribute.getKey()); } - ICustomAttribute instance = new PlayerAttribute(attribute, baseValue); + PlayerAttribute instance = new PlayerAttribute(attribute, baseValue); map.put(attribute, instance); return instance; } - public ICustomAttribute getAttributeInstance(AttributeDefinition attribute) { + public PlayerAttribute getAttributeInstance(AttributeDefinition attribute) { return map.get(attribute); } - - public Collection getAllAttributes() { - return map.values(); - } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/IRequirementChecker.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/IRequirementChecker.java index d7afb5e59..76b6f0b19 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/IRequirementChecker.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/IRequirementChecker.java @@ -11,6 +11,8 @@ public interface IRequirementChecker { String getTooltipValue(NBTTagCompound nbt); + Object getValue(NBTTagCompound nbt); + void apply(NBTTagCompound nbt, Object value); /** diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/types/QuestActiveRequirement.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/types/QuestActiveRequirement.java index af286a56a..679d28add 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/types/QuestActiveRequirement.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/types/QuestActiveRequirement.java @@ -29,6 +29,14 @@ public class QuestActiveRequirement implements IRequirementChecker { return "null"; } + @Override + public Object getValue(NBTTagCompound nbt) { + if (nbt.hasKey(getKey())) { + return nbt.getInteger(getKey()); + } + return null; + } + @Override public void apply(NBTTagCompound nbt, Object value) { if (value instanceof Integer) { diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/types/QuestCompletedRequirement.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/types/QuestCompletedRequirement.java index e2c887659..6befd0311 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/types/QuestCompletedRequirement.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/types/QuestCompletedRequirement.java @@ -36,6 +36,14 @@ public class QuestCompletedRequirement implements IRequirementChecker { } } + @Override + public Object getValue(NBTTagCompound nbt) { + if (nbt.hasKey(getKey())) { + return nbt.getInteger(getKey()); + } + return null; + } + @Override public boolean check(EntityPlayer player, NBTTagCompound nbt) { if (nbt.hasKey(getKey())) { diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/tracker/PlayerAttributeTracker.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/tracker/PlayerAttributeTracker.java index 542a34e2c..58c3f4f62 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/tracker/PlayerAttributeTracker.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/tracker/PlayerAttributeTracker.java @@ -3,7 +3,9 @@ package kamkeel.npcs.controllers.data.attribute.tracker; import kamkeel.npcs.CustomAttributes; import kamkeel.npcs.controllers.AttributeController; import kamkeel.npcs.controllers.data.attribute.AttributeDefinition; -import kamkeel.npcs.controllers.data.attribute.ICustomAttribute; +import kamkeel.npcs.controllers.data.attribute.PlayerAttribute; +import noppes.npcs.api.entity.IPlayer; +import noppes.npcs.api.handler.data.ICustomAttribute; import kamkeel.npcs.controllers.data.attribute.PlayerAttributeMap; import kamkeel.npcs.controllers.data.attribute.requirement.RequirementCheckerRegistry; import kamkeel.npcs.util.AttributeAttackUtil; @@ -14,13 +16,14 @@ import net.minecraft.entity.ai.attributes.IAttributeInstance; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.api.handler.data.IPlayerAttributes; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; -public class PlayerAttributeTracker { +public class PlayerAttributeTracker implements IPlayerAttributes { public static UUID healthUUID = UUID.fromString("48a0ad75-2cf8-4838-ad2f-9a0aadc57dfe"); public static UUID healthBoostUUID = UUID.fromString("93cfba41-294a-4e6b-a98b-bee76a9f813b"); @@ -50,10 +53,6 @@ public class PlayerAttributeTracker { recalcAttributes(null); } - public PlayerAttributeMap getPlayerAttributes() { - return playerAttributes; - } - public void recalcAttributes(EntityPlayer player) { // Reset aggregated attributes and magic maps. playerAttributes = new PlayerAttributeMap(); @@ -83,11 +82,11 @@ public class PlayerAttributeTracker { float value = entry.getValue(); AttributeDefinition def = AttributeController.getAttribute(key); if (def != null) { - ICustomAttribute inst = playerAttributes.getAttributeInstance(def); + PlayerAttribute inst = playerAttributes.getAttributeInstance(def); if (inst == null) { inst = playerAttributes.registerAttribute(def, 0.0f); } - inst.setValue(inst.getValue() + value); + inst.value = (inst.getValue() + value); } } // Process Magic @@ -217,4 +216,43 @@ public class PlayerAttributeTracker { ICustomAttribute inst = playerAttributes.getAttributeInstance(def); return inst != null ? inst.getValue() : 0.0f; } + + public void recalculate(IPlayer player) { + if(player == null || player.getMCEntity() == null) + return; + + recalcAttributes((EntityPlayer) player.getMCEntity()); + } + + public ICustomAttribute[] getAttributes() { + return playerAttributes.map.values().toArray(new ICustomAttribute[playerAttributes.map.size()]); + } + + public float getAttributeValue(String key) { + for (ICustomAttribute inst : getAttributes()) { + if (inst.getAttribute().getKey().equalsIgnoreCase(key)) { + return inst.getValue(); + } + } + return 0.0f; + } + + + public boolean hasAttribute(String key) { + for (ICustomAttribute inst : getAttributes()) { + if (inst.getAttribute().getKey().equalsIgnoreCase(key)) { + return true; + } + } + return false; + } + + public ICustomAttribute getAttribute(String key) { + for (ICustomAttribute inst : getAttributes()) { + if (inst.getAttribute().getKey().equalsIgnoreCase(key)) { + return inst; + } + } + return null; + } } diff --git a/src/main/java/noppes/npcs/scripted/NpcAPI.java b/src/main/java/noppes/npcs/scripted/NpcAPI.java index ceb055867..7531bed81 100644 --- a/src/main/java/noppes/npcs/scripted/NpcAPI.java +++ b/src/main/java/noppes/npcs/scripted/NpcAPI.java @@ -3,6 +3,7 @@ package noppes.npcs.scripted; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.eventhandler.EventBus; import foxz.command.ScriptedCommand; +import kamkeel.npcs.controllers.AttributeController; import kamkeel.npcs.controllers.ProfileController; import net.minecraft.block.Block; import net.minecraft.command.CommandHandler; @@ -261,6 +262,10 @@ public class NpcAPI extends AbstractNpcAPI { return PartyController.Instance(); } + public IAttributeHandler getAttributeHandler() { + return AttributeController.Instance; + } + public ITransportHandler getLocations() { return TransportController.getInstance(); } diff --git a/src/main/java/noppes/npcs/scripted/entity/ScriptPlayer.java b/src/main/java/noppes/npcs/scripted/entity/ScriptPlayer.java index 5c637dc8c..c1be3c0f9 100644 --- a/src/main/java/noppes/npcs/scripted/entity/ScriptPlayer.java +++ b/src/main/java/noppes/npcs/scripted/entity/ScriptPlayer.java @@ -1,5 +1,6 @@ package noppes.npcs.scripted.entity; +import kamkeel.npcs.controllers.AttributeController; import kamkeel.npcs.network.PacketHandler; import kamkeel.npcs.network.packets.data.AchievementPacket; import kamkeel.npcs.network.packets.data.ChatAlertPacket; @@ -836,4 +837,6 @@ public class ScriptPlayer extends ScriptLivingBase public IMagicData getMagicData() { return this.getData().magicData; } + + public IPlayerAttributes getAttributes(){ return AttributeController.getTracker(this.player); } } diff --git a/src/main/java/noppes/npcs/scripted/item/ScriptItemStack.java b/src/main/java/noppes/npcs/scripted/item/ScriptItemStack.java index 1ec97af1f..8e80f3eb6 100644 --- a/src/main/java/noppes/npcs/scripted/item/ScriptItemStack.java +++ b/src/main/java/noppes/npcs/scripted/item/ScriptItemStack.java @@ -1,6 +1,9 @@ package noppes.npcs.scripted.item; import com.google.common.collect.Multimap; +import kamkeel.npcs.controllers.data.attribute.requirement.IRequirementChecker; +import kamkeel.npcs.controllers.data.attribute.requirement.RequirementCheckerRegistry; +import kamkeel.npcs.util.AttributeItemUtil; import net.minecraft.block.Block; import net.minecraft.enchantment.Enchantment; import net.minecraft.entity.ai.attributes.AttributeModifier; @@ -22,10 +25,7 @@ import noppes.npcs.scripted.CustomNPCsException; import noppes.npcs.scripted.NpcAPI; import noppes.npcs.scripted.ScriptNbt; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; public class ScriptItemStack implements IItemStack { public ItemStack item; @@ -454,4 +454,131 @@ public class ScriptItemStack implements IItemStack { public boolean compare(IItemStack item, boolean ignoreDamage, boolean ignoreNBT) { return NoppesUtilPlayer.compareItems(getMCItemStack(), item.getMCItemStack(), ignoreDamage, ignoreNBT); } + + @Override + public void setCustomAttribute(String key, double value) { + AttributeItemUtil.applyAttribute(item, key, (float) value); + } + + @Override + public boolean hasCustomAttribute(String key) { + return AttributeItemUtil.readAttributes(item).containsKey(key); + } + + @Override + public float getCustomAttribute(String key) { + return hasCustomAttribute(key) ? AttributeItemUtil.readAttributes(item).get(key) : 0.0f; + } + + @Override + public void removeCustomAttribute(String key) { + AttributeItemUtil.removeAttribute(item, key); + } + + @Override + public void setMagicAttribute(String key, int magicId, double value) { + AttributeItemUtil.writeMagicAttribute(item, key, magicId, (float) value); + } + + @Override + public float getMagicAttribute(String key, int magicId) { + Map magicMap = AttributeItemUtil.readMagicAttributeMap(item, key); + return magicMap.getOrDefault(magicId, 0.0f); + } + + @Override + public boolean hasMagicAttribute(String key, int magicId) { + Map magicMap = AttributeItemUtil.readMagicAttributeMap(item, key); + return magicMap.containsKey(magicId); + } + + @Override + public void removeMagicAttribute(String key, int magicId) { + AttributeItemUtil.removeMagicAttribute(item, key, magicId); + } + + @Override + public void setRequirement(String reqKey, Object value) { + // Delegate to the utility method that applies the requirement into the item's NBT. + AttributeItemUtil.applyRequirement(item, reqKey, value); + } + + @Override + public boolean hasRequirement(String reqKey) { + if (item == null || item.stackTagCompound == null) + return false; + NBTTagCompound root = item.stackTagCompound; + if (!root.hasKey(AttributeItemUtil.TAG_RPGCORE)) + return false; + NBTTagCompound rpgCore = root.getCompoundTag(AttributeItemUtil.TAG_RPGCORE); + if (!rpgCore.hasKey(AttributeItemUtil.TAG_REQUIREMENTS)) + return false; + NBTTagCompound reqTag = rpgCore.getCompoundTag(AttributeItemUtil.TAG_REQUIREMENTS); + return reqTag.hasKey(reqKey); + } + + @Override + public Object getRequirement(String reqKey) { + if (item == null || item.stackTagCompound == null) + return null; + NBTTagCompound root = item.stackTagCompound; + if (!root.hasKey(AttributeItemUtil.TAG_RPGCORE)) + return null; + NBTTagCompound rpgCore = root.getCompoundTag(AttributeItemUtil.TAG_RPGCORE); + if (!rpgCore.hasKey(AttributeItemUtil.TAG_REQUIREMENTS)) + return null; + NBTTagCompound reqTag = rpgCore.getCompoundTag(AttributeItemUtil.TAG_REQUIREMENTS); + if (reqTag.hasKey(reqKey)) { + IRequirementChecker checker = RequirementCheckerRegistry.getChecker(reqKey); + if (checker != null) { + return checker.getValue(reqTag); + } + // If no checker exists, fall back to returning the raw stored value. + NBTBase tag = reqTag.getTag(reqKey); + if (tag instanceof NBTPrimitive) + return ((NBTPrimitive) tag).func_150286_g(); + if (tag instanceof NBTTagString) + return ((NBTTagString) tag).func_150285_a_(); + return tag; + } + return null; + } + + @Override + public void removeRequirement(String reqKey) { + AttributeItemUtil.removeRequirement(item, reqKey); + } + + @Override + public String[] getCustomAttributeKeys() { + Map attrs = AttributeItemUtil.readAttributes(item); + return attrs.keySet().toArray(new String[attrs.size()]); + } + + @Override + public String[] getMagicAttributeKeys(String key) { + Map magicMap = AttributeItemUtil.readMagicAttributeMap(item, key); + // Convert the integer magic IDs to strings. + String[] keys = new String[magicMap.size()]; + int i = 0; + for (Integer magicId : magicMap.keySet()) { + keys[i++] = magicId.toString(); + } + return keys; + } + + @Override + public String[] getRequirementKeys() { + if (item == null || item.stackTagCompound == null) + return new String[0]; + NBTTagCompound root = item.stackTagCompound; + if (!root.hasKey(AttributeItemUtil.TAG_RPGCORE)) + return new String[0]; + NBTTagCompound rpgCore = root.getCompoundTag(AttributeItemUtil.TAG_RPGCORE); + if (!rpgCore.hasKey(AttributeItemUtil.TAG_REQUIREMENTS)) + return new String[0]; + NBTTagCompound reqTag = rpgCore.getCompoundTag(AttributeItemUtil.TAG_REQUIREMENTS); + Set keys = reqTag.func_150296_c(); + return keys.toArray(new String[keys.size()]); + } }