diff --git a/src/api b/src/api index ed5640d23..48cfcb3ea 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit ed5640d2385d5626a8dff2dd2d0bc59b6c455f4c +Subproject commit 48cfcb3ea529e79b0ba18fdd4ba768bf6275c75e diff --git a/src/main/java/noppes/npcs/CustomNpcs.java b/src/main/java/noppes/npcs/CustomNpcs.java index 4b5750c6a..934d13385 100644 --- a/src/main/java/noppes/npcs/CustomNpcs.java +++ b/src/main/java/noppes/npcs/CustomNpcs.java @@ -62,6 +62,7 @@ import noppes.npcs.controllers.PlayerDataController; import noppes.npcs.controllers.QuestController; import noppes.npcs.controllers.RecipeController; import noppes.npcs.controllers.ScriptController; +import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.controllers.ServerCloneController; import noppes.npcs.controllers.ServerTagMapController; import noppes.npcs.controllers.SpawnController; @@ -180,6 +181,7 @@ public class CustomNpcs { MinecraftForge.EVENT_BUS.register(new ServerEventsHandler()); MinecraftForge.EVENT_BUS.register(new ScriptController()); + new ScriptHookController(); ScriptPlayerEventHandler scriptPlayerEventHandler = new ScriptPlayerEventHandler(); MinecraftForge.EVENT_BUS.register(scriptPlayerEventHandler); diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiNPCEventScripts.java b/src/main/java/noppes/npcs/client/gui/script/GuiNPCEventScripts.java index 5b4693a10..8577a080c 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiNPCEventScripts.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiNPCEventScripts.java @@ -3,7 +3,9 @@ package noppes.npcs.client.gui.script; import kamkeel.npcs.network.packets.request.script.EventScriptPacket; import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.NBTTags; +import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.controllers.ScriptContainer; +import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.controllers.data.DataScript; import noppes.npcs.entity.EntityNPCInterface; @@ -14,24 +16,7 @@ public class GuiNPCEventScripts extends GuiScriptInterface { private final DataScript script; public GuiNPCEventScripts(EntityNPCInterface npc) { - this.hookList = new ArrayList<>(); - hookList.add("init"); - hookList.add("tick"); - hookList.add("interact"); - hookList.add("dialog"); - hookList.add("damaged"); - hookList.add("killed"); - hookList.add("meleeAttack"); - hookList.add("meleeSwing"); - hookList.add("rangedLaunched"); - hookList.add("target"); - hookList.add("collide"); - hookList.add("kills"); - hookList.add("dialogClose"); - hookList.add("timer"); - hookList.add("targetLost"); - hookList.add("projectileTick"); - hookList.add("projectileImpact"); + this.hookList = new ArrayList<>(ScriptHookController.Instance.getAllHooks(IScriptHookHandler.CONTEXT_NPC)); this.script = new DataScript(npc); this.handler = this.script; diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiScriptAllNPCs.java b/src/main/java/noppes/npcs/client/gui/script/GuiScriptAllNPCs.java index 6f0927cbc..fd2e366fc 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptAllNPCs.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptAllNPCs.java @@ -3,32 +3,19 @@ package noppes.npcs.client.gui.script; import kamkeel.npcs.network.packets.request.script.GlobalNPCScriptPacket; import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.NBTTags; +import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.controllers.ScriptContainer; +import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.controllers.data.GlobalNPCDataScript; +import java.util.ArrayList; import java.util.List; public class GuiScriptAllNPCs extends GuiScriptInterface { private final GlobalNPCDataScript script = new GlobalNPCDataScript(null); public GuiScriptAllNPCs() { - hookList.add("init"); - hookList.add("tick"); - hookList.add("interact"); - hookList.add("dialog"); - hookList.add("damaged"); - hookList.add("killed"); - hookList.add("meleeAttack"); - hookList.add("meleeSwing"); - hookList.add("rangedLaunched"); - hookList.add("target"); - hookList.add("collide"); - hookList.add("kills"); - hookList.add("dialogClose"); - hookList.add("timer"); - hookList.add("targetLost"); - hookList.add("projectileTick"); - hookList.add("projectileImpact"); + this.hookList = new ArrayList<>(ScriptHookController.Instance.getAllHooks(IScriptHookHandler.CONTEXT_GLOBAL_NPC)); this.handler = this.script; GlobalNPCScriptPacket.Get(); diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiScriptBlock.java b/src/main/java/noppes/npcs/client/gui/script/GuiScriptBlock.java index d5a5f3f86..a97efa90f 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptBlock.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptBlock.java @@ -2,26 +2,18 @@ package noppes.npcs.client.gui.script; import kamkeel.npcs.network.packets.request.script.BlockScriptPacket; import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.blocks.tiles.TileScripted; +import noppes.npcs.controllers.ScriptHookController; + +import java.util.ArrayList; public class GuiScriptBlock extends GuiScriptInterface { private final TileScripted tileScripted; public GuiScriptBlock(int x, int y, int z) { - hookList.add("init"); - hookList.add("tick"); - hookList.add("interact"); - hookList.add("fallenUpon"); - hookList.add("redstone"); - hookList.add("broken"); - hookList.add("exploded"); - hookList.add("rainFilled"); - hookList.add("neighborChanged"); - hookList.add("clicked"); - hookList.add("harvested"); - hookList.add("collide"); - hookList.add("timer"); + this.hookList = new ArrayList<>(ScriptHookController.Instance.getAllHooks(IScriptHookHandler.CONTEXT_BLOCK)); this.handler = this.tileScripted = (TileScripted) player.worldObj.getTileEntity(x, y, z); BlockScriptPacket.Get(tileScripted.xCoord, tileScripted.yCoord, tileScripted.zCoord); diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiScriptEffect.java b/src/main/java/noppes/npcs/client/gui/script/GuiScriptEffect.java index 33582ad88..f4fb80846 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptEffect.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptEffect.java @@ -24,7 +24,9 @@ import noppes.npcs.client.gui.util.IGuiData; import noppes.npcs.client.gui.util.IJTextAreaListener; import noppes.npcs.client.gui.util.ITextChangeListener; import noppes.npcs.client.gui.util.ITextfieldListener; +import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.controllers.ScriptContainer; +import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.controllers.data.CustomEffect; import noppes.npcs.controllers.data.EffectScript; @@ -58,9 +60,7 @@ public class GuiScriptEffect extends GuiNPCInterface implements GuiYesNoCallback this.effect = effect; this.scriptHandler = new EffectScript(); - for (EffectScript.ScriptType type : EffectScript.ScriptType.values()) { - this.hookList.add(type.function); - } + this.hookList = new ArrayList<>(ScriptHookController.Instance.getAllHooks(IScriptHookHandler.CONTEXT_EFFECT)); EffectScriptPacket.Get(effect.id); } diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiScriptForge.java b/src/main/java/noppes/npcs/client/gui/script/GuiScriptForge.java index aea39d1a5..01a179d54 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptForge.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptForge.java @@ -13,7 +13,9 @@ import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.ChunkWatchEvent; import net.minecraftforge.event.world.WorldEvent; import noppes.npcs.NBTTags; +import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.controllers.ScriptContainer; +import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.controllers.data.ForgeDataScript; import org.apache.commons.lang3.StringUtils; @@ -28,8 +30,10 @@ public class GuiScriptForge extends GuiScriptInterface { private final ForgeDataScript script = new ForgeDataScript(); public GuiScriptForge() { - hookList.add("init"); + // Add built-in "init" hook from controller + hookList.addAll(ScriptHookController.Instance.getBuiltInHooks(IScriptHookHandler.CONTEXT_FORGE)); + // Dynamically discover Forge event hooks ArrayList list = new ArrayList(); try { list.addAll(ClassPath.from(this.getClass().getClassLoader()).getTopLevelClassesRecursive("cpw.mods.fml.common.gameevent")); @@ -60,6 +64,13 @@ public class GuiScriptForge extends GuiScriptInterface { } hookList.add("onCNPCNaturalSpawn"); + // Add any addon-registered hooks for the forge context + for (String addonHook : ScriptHookController.Instance.getAddonHooks(IScriptHookHandler.CONTEXT_FORGE)) { + if (!hookList.contains(addonHook)) { + hookList.add(addonHook); + } + } + this.handler = this.script; ForgeScriptPacket.Get(); } diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiScriptItem.java b/src/main/java/noppes/npcs/client/gui/script/GuiScriptItem.java index 23a29b90c..8b2a423cf 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptItem.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptItem.java @@ -6,8 +6,11 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.CustomItems; import noppes.npcs.NBTTags; +import noppes.npcs.api.handler.IScriptHookHandler; +import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.scripted.item.ScriptCustomItem; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; @@ -18,18 +21,7 @@ public class GuiScriptItem extends GuiScriptInterface { public static Map consoleText = new HashMap<>(); public GuiScriptItem() { - hookList.add("init"); - hookList.add("tick"); - hookList.add("tossed"); - hookList.add("pickedUp"); - hookList.add("spawn"); - hookList.add("interact"); - hookList.add("rightClick"); - hookList.add("attack"); - hookList.add("startItem"); - hookList.add("usingItem"); - hookList.add("stopItem"); - hookList.add("finishItem"); + this.hookList = new ArrayList<>(ScriptHookController.Instance.getAllHooks(IScriptHookHandler.CONTEXT_ITEM)); this.handler = this.item = new ScriptCustomItem(new ItemStack(CustomItems.scripted_item)); ItemScriptErrorPacket.Get(); diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiScriptLinkedItem.java b/src/main/java/noppes/npcs/client/gui/script/GuiScriptLinkedItem.java index 664c08d1f..2e168f3fa 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptLinkedItem.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptLinkedItem.java @@ -24,8 +24,9 @@ import noppes.npcs.client.gui.util.IGuiData; import noppes.npcs.client.gui.util.IJTextAreaListener; import noppes.npcs.client.gui.util.ITextChangeListener; import noppes.npcs.client.gui.util.ITextfieldListener; -import noppes.npcs.constants.EnumScriptType; +import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.controllers.ScriptContainer; +import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.controllers.data.LinkedItem; import noppes.npcs.controllers.data.LinkedItemScript; @@ -59,20 +60,7 @@ public class GuiScriptLinkedItem extends GuiNPCInterface implements GuiYesNoCall this.linkedItem = linkedItem; this.scriptHandler = new LinkedItemScript(); - hookList.add(EnumScriptType.LINKED_ITEM_BUILD.function); - hookList.add(EnumScriptType.LINKED_ITEM_VERSION.function); - hookList.add(EnumScriptType.INIT.function); - hookList.add(EnumScriptType.TICK.function); - hookList.add(EnumScriptType.TOSSED.function); - hookList.add(EnumScriptType.PICKEDUP.function); - hookList.add(EnumScriptType.SPAWN.function); - hookList.add(EnumScriptType.INTERACT.function); - hookList.add(EnumScriptType.RIGHT_CLICK.function); - hookList.add(EnumScriptType.ATTACK.function); - hookList.add(EnumScriptType.START_USING_ITEM.function); - hookList.add(EnumScriptType.USING_ITEM.function); - hookList.add(EnumScriptType.STOP_USING_ITEM.function); - hookList.add(EnumScriptType.FINISH_USING_ITEM.function); + this.hookList = new ArrayList<>(ScriptHookController.Instance.getAllHooks(IScriptHookHandler.CONTEXT_LINKED_ITEM)); LinkedItemScriptPacket.Get(linkedItem.id); } diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiScriptPlayers.java b/src/main/java/noppes/npcs/client/gui/script/GuiScriptPlayers.java index 501e348d1..e0dfc8366 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptPlayers.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptPlayers.java @@ -4,87 +4,19 @@ import kamkeel.npcs.network.packets.request.script.PlayerScriptPacket; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.NBTTags; -import noppes.npcs.constants.EnumScriptType; +import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.controllers.ScriptContainer; -import noppes.npcs.controllers.data.EffectScript; +import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.controllers.data.PlayerDataScript; +import java.util.ArrayList; import java.util.List; public class GuiScriptPlayers extends GuiScriptInterface { private PlayerDataScript script = new PlayerDataScript((EntityPlayer) null); public GuiScriptPlayers() { - hookList.add(EnumScriptType.INIT.function); - hookList.add(EnumScriptType.TICK.function); - hookList.add(EnumScriptType.INTERACT.function); - hookList.add(EnumScriptType.RIGHT_CLICK.function); - hookList.add(EnumScriptType.ATTACK.function); - hookList.add(EnumScriptType.ATTACKED.function); - hookList.add(EnumScriptType.DAMAGED_ENTITY.function); - hookList.add(EnumScriptType.DAMAGED.function); - hookList.add(EnumScriptType.KILLS.function); - hookList.add(EnumScriptType.KILLED.function); - hookList.add(EnumScriptType.DROP.function); - hookList.add(EnumScriptType.RESPAWN.function); - hookList.add(EnumScriptType.BREAK_BLOCK.function); - hookList.add(EnumScriptType.CHAT.function); - hookList.add(EnumScriptType.LOGIN.function); - hookList.add(EnumScriptType.LOGOUT.function); - hookList.add(EnumScriptType.KEY_PRESSED.function); - hookList.add(EnumScriptType.MOUSE_CLICKED.function); - hookList.add(EnumScriptType.TOSS.function); - hookList.add(EnumScriptType.PICKUP.function); - hookList.add(EnumScriptType.PICKUP_XP.function); - hookList.add(EnumScriptType.RANGED_CHARGE.function); - hookList.add(EnumScriptType.RANGED_LAUNCHED.function); - hookList.add(EnumScriptType.TIMER.function); - hookList.add(EnumScriptType.START_USING_ITEM.function); - hookList.add(EnumScriptType.USING_ITEM.function); - hookList.add(EnumScriptType.STOP_USING_ITEM.function); - hookList.add(EnumScriptType.FINISH_USING_ITEM.function); - hookList.add(EnumScriptType.CONTAINER_OPEN.function); - hookList.add(EnumScriptType.USE_HOE.function); - hookList.add(EnumScriptType.BONEMEAL.function); - hookList.add(EnumScriptType.FILL_BUCKET.function); - hookList.add(EnumScriptType.JUMP.function); - hookList.add(EnumScriptType.FALL.function); - hookList.add(EnumScriptType.WAKE_UP.function); - hookList.add(EnumScriptType.SLEEP.function); - hookList.add(EnumScriptType.PLAYSOUND.function); - hookList.add(EnumScriptType.LIGHTNING.function); - hookList.add(EnumScriptType.CHANGED_DIM.function); - hookList.add(EnumScriptType.QUEST_START.function); - hookList.add(EnumScriptType.QUEST_COMPLETED.function); - hookList.add(EnumScriptType.QUEST_TURNIN.function); - hookList.add(EnumScriptType.FACTION_POINTS.function); - hookList.add(EnumScriptType.DIALOG_OPEN.function); - hookList.add(EnumScriptType.DIALOG_OPTION.function); - hookList.add(EnumScriptType.DIALOG_CLOSE.function); - hookList.add(EnumScriptType.SCRIPT_COMMAND.function); - hookList.add(EnumScriptType.CUSTOM_GUI_CLOSED.function); - hookList.add(EnumScriptType.CUSTOM_GUI_BUTTON.function); - hookList.add(EnumScriptType.CUSTOM_GUI_SLOT.function); - hookList.add(EnumScriptType.CUSTOM_GUI_SLOT_CLICKED.function); - hookList.add(EnumScriptType.CUSTOM_GUI_SCROLL.function); - hookList.add(EnumScriptType.CUSTOM_GUI_TEXTFIELD.function); - hookList.add(EnumScriptType.PARTY_QUEST_COMPLETED.function); - hookList.add(EnumScriptType.PARTY_QUEST_SET.function); - hookList.add(EnumScriptType.PARTY_QUEST_TURNED_IN.function); - hookList.add(EnumScriptType.PARTY_INVITE.function); - hookList.add(EnumScriptType.PARTY_KICK.function); - hookList.add(EnumScriptType.PARTY_LEAVE.function); - hookList.add(EnumScriptType.PARTY_DISBAND.function); - hookList.add(EnumScriptType.ANIMATION_START.function); - hookList.add(EnumScriptType.ANIMATION_END.function); - hookList.add(EnumScriptType.ANIMATION_FRAME_ENTER.function); - hookList.add(EnumScriptType.ANIMATION_FRAME_EXIT.function); - hookList.add(EnumScriptType.PROFILE_CHANGE.function); - hookList.add(EnumScriptType.PROFILE_REMOVE.function); - hookList.add(EnumScriptType.PROFILE_CREATE.function); - hookList.add(EffectScript.ScriptType.OnEffectAdd.function); - hookList.add(EffectScript.ScriptType.OnEffectTick.function); - hookList.add(EffectScript.ScriptType.OnEffectRemove.function); + this.hookList = new ArrayList<>(ScriptHookController.Instance.getAllHooks(IScriptHookHandler.CONTEXT_PLAYER)); this.handler = this.script; PlayerScriptPacket.Get(); diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiScriptRecipe.java b/src/main/java/noppes/npcs/client/gui/script/GuiScriptRecipe.java index bb93052d7..4acdb02e4 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptRecipe.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptRecipe.java @@ -24,7 +24,9 @@ import noppes.npcs.client.gui.util.IGuiData; import noppes.npcs.client.gui.util.IJTextAreaListener; import noppes.npcs.client.gui.util.ITextChangeListener; import noppes.npcs.client.gui.util.ITextfieldListener; +import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.controllers.ScriptContainer; +import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.controllers.data.RecipeAnvil; import noppes.npcs.controllers.data.RecipeCarpentry; import noppes.npcs.controllers.data.RecipeScript; @@ -62,8 +64,7 @@ public class GuiScriptRecipe extends GuiNPCInterface implements GuiYesNoCallback this.anvil = false; this.recipeId = recipe.id; - hookList.add(RecipeScript.ScriptType.PRE.function); - hookList.add(RecipeScript.ScriptType.POST.function); + this.hookList = new ArrayList<>(ScriptHookController.Instance.getAllHooks(IScriptHookHandler.CONTEXT_RECIPE)); RecipeScriptPacket.Get(false, recipeId); } @@ -80,8 +81,7 @@ public class GuiScriptRecipe extends GuiNPCInterface implements GuiYesNoCallback this.anvil = true; this.recipeId = recipe.id; - hookList.add(RecipeScript.ScriptType.PRE.function); - hookList.add(RecipeScript.ScriptType.POST.function); + this.hookList = new ArrayList<>(ScriptHookController.Instance.getAllHooks(IScriptHookHandler.CONTEXT_RECIPE)); RecipeScriptPacket.Get(true, recipeId); } diff --git a/src/main/java/noppes/npcs/controllers/ScriptHookController.java b/src/main/java/noppes/npcs/controllers/ScriptHookController.java new file mode 100644 index 000000000..7698a6d2a --- /dev/null +++ b/src/main/java/noppes/npcs/controllers/ScriptHookController.java @@ -0,0 +1,362 @@ +package noppes.npcs.controllers; + +import noppes.npcs.api.handler.IScriptHookHandler; +import noppes.npcs.constants.EnumScriptType; +import noppes.npcs.controllers.data.EffectScript; +import noppes.npcs.controllers.data.RecipeScript; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Controller for managing script hooks. + * Allows addon mods to register custom hooks that appear in script editor GUIs. + */ +public class ScriptHookController implements IScriptHookHandler { + + public static ScriptHookController Instance; + + // Built-in hooks per context + private final Map> builtInHooks = new HashMap<>(); + + // Addon-registered hooks per context + private final Map> addonHooks = new HashMap<>(); + + // All available contexts + private static final String[] CONTEXTS = { + CONTEXT_NPC, + CONTEXT_PLAYER, + CONTEXT_BLOCK, + CONTEXT_ITEM, + CONTEXT_LINKED_ITEM, + CONTEXT_FORGE, + CONTEXT_GLOBAL_NPC, + CONTEXT_RECIPE, + CONTEXT_EFFECT + }; + + public ScriptHookController() { + Instance = this; + initializeBuiltInHooks(); + } + + private void initializeBuiltInHooks() { + // Initialize empty lists for all contexts + for (String context : CONTEXTS) { + builtInHooks.put(context, new ArrayList<>()); + addonHooks.put(context, new ArrayList<>()); + } + + // NPC hooks + registerBuiltIn(CONTEXT_NPC, + EnumScriptType.INIT.function, + EnumScriptType.TICK.function, + EnumScriptType.INTERACT.function, + EnumScriptType.DIALOG.function, + EnumScriptType.DAMAGED.function, + EnumScriptType.KILLED.function, + EnumScriptType.ATTACK_MELEE.function, + EnumScriptType.ATTACK_SWING.function, + EnumScriptType.RANGED_LAUNCHED.function, + EnumScriptType.TARGET.function, + EnumScriptType.COLLIDE.function, + EnumScriptType.KILLS.function, + EnumScriptType.DIALOG_CLOSE.function, + EnumScriptType.TIMER.function, + EnumScriptType.TARGET_LOST.function, + EnumScriptType.PROJECTILE_TICK.function, + EnumScriptType.PROJECTILE_IMPACT.function + ); + + // Global NPC hooks (same as NPC) + registerBuiltIn(CONTEXT_GLOBAL_NPC, + EnumScriptType.INIT.function, + EnumScriptType.TICK.function, + EnumScriptType.INTERACT.function, + EnumScriptType.DIALOG.function, + EnumScriptType.DAMAGED.function, + EnumScriptType.KILLED.function, + EnumScriptType.ATTACK_MELEE.function, + EnumScriptType.ATTACK_SWING.function, + EnumScriptType.RANGED_LAUNCHED.function, + EnumScriptType.TARGET.function, + EnumScriptType.COLLIDE.function, + EnumScriptType.KILLS.function, + EnumScriptType.DIALOG_CLOSE.function, + EnumScriptType.TIMER.function, + EnumScriptType.TARGET_LOST.function, + EnumScriptType.PROJECTILE_TICK.function, + EnumScriptType.PROJECTILE_IMPACT.function + ); + + // Player hooks + registerBuiltIn(CONTEXT_PLAYER, + EnumScriptType.INIT.function, + EnumScriptType.TICK.function, + EnumScriptType.INTERACT.function, + EnumScriptType.RIGHT_CLICK.function, + EnumScriptType.ATTACK.function, + EnumScriptType.ATTACKED.function, + EnumScriptType.DAMAGED_ENTITY.function, + EnumScriptType.DAMAGED.function, + EnumScriptType.KILLS.function, + EnumScriptType.KILLED.function, + EnumScriptType.DROP.function, + EnumScriptType.RESPAWN.function, + EnumScriptType.BREAK_BLOCK.function, + EnumScriptType.CHAT.function, + EnumScriptType.LOGIN.function, + EnumScriptType.LOGOUT.function, + EnumScriptType.KEY_PRESSED.function, + EnumScriptType.MOUSE_CLICKED.function, + EnumScriptType.TOSS.function, + EnumScriptType.PICKUP.function, + EnumScriptType.PICKUP_XP.function, + EnumScriptType.RANGED_CHARGE.function, + EnumScriptType.RANGED_LAUNCHED.function, + EnumScriptType.TIMER.function, + EnumScriptType.START_USING_ITEM.function, + EnumScriptType.USING_ITEM.function, + EnumScriptType.STOP_USING_ITEM.function, + EnumScriptType.FINISH_USING_ITEM.function, + EnumScriptType.CONTAINER_OPEN.function, + EnumScriptType.USE_HOE.function, + EnumScriptType.BONEMEAL.function, + EnumScriptType.FILL_BUCKET.function, + EnumScriptType.JUMP.function, + EnumScriptType.FALL.function, + EnumScriptType.WAKE_UP.function, + EnumScriptType.SLEEP.function, + EnumScriptType.PLAYSOUND.function, + EnumScriptType.LIGHTNING.function, + EnumScriptType.CHANGED_DIM.function, + EnumScriptType.QUEST_START.function, + EnumScriptType.QUEST_COMPLETED.function, + EnumScriptType.QUEST_TURNIN.function, + EnumScriptType.FACTION_POINTS.function, + EnumScriptType.DIALOG_OPEN.function, + EnumScriptType.DIALOG_OPTION.function, + EnumScriptType.DIALOG_CLOSE.function, + EnumScriptType.SCRIPT_COMMAND.function, + EnumScriptType.CUSTOM_GUI_CLOSED.function, + EnumScriptType.CUSTOM_GUI_BUTTON.function, + EnumScriptType.CUSTOM_GUI_SLOT.function, + EnumScriptType.CUSTOM_GUI_SLOT_CLICKED.function, + EnumScriptType.CUSTOM_GUI_SCROLL.function, + EnumScriptType.CUSTOM_GUI_TEXTFIELD.function, + EnumScriptType.PARTY_QUEST_COMPLETED.function, + EnumScriptType.PARTY_QUEST_SET.function, + EnumScriptType.PARTY_QUEST_TURNED_IN.function, + EnumScriptType.PARTY_INVITE.function, + EnumScriptType.PARTY_KICK.function, + EnumScriptType.PARTY_LEAVE.function, + EnumScriptType.PARTY_DISBAND.function, + EnumScriptType.ANIMATION_START.function, + EnumScriptType.ANIMATION_END.function, + EnumScriptType.ANIMATION_FRAME_ENTER.function, + EnumScriptType.ANIMATION_FRAME_EXIT.function, + EnumScriptType.PROFILE_CHANGE.function, + EnumScriptType.PROFILE_REMOVE.function, + EnumScriptType.PROFILE_CREATE.function, + EffectScript.ScriptType.OnEffectAdd.function, + EffectScript.ScriptType.OnEffectTick.function, + EffectScript.ScriptType.OnEffectRemove.function + ); + + // Block hooks + registerBuiltIn(CONTEXT_BLOCK, + EnumScriptType.INIT.function, + EnumScriptType.TICK.function, + EnumScriptType.INTERACT.function, + EnumScriptType.FALLEN_UPON.function, + EnumScriptType.REDSTONE.function, + EnumScriptType.BROKEN.function, + EnumScriptType.EXPLODED.function, + EnumScriptType.RAIN_FILLED.function, + EnumScriptType.NEIGHBOR_CHANGED.function, + EnumScriptType.CLICKED.function, + EnumScriptType.HARVESTED.function, + EnumScriptType.COLLIDE.function, + EnumScriptType.TIMER.function + ); + + // Item hooks + registerBuiltIn(CONTEXT_ITEM, + EnumScriptType.INIT.function, + EnumScriptType.TICK.function, + EnumScriptType.TOSSED.function, + EnumScriptType.PICKEDUP.function, + EnumScriptType.SPAWN.function, + EnumScriptType.INTERACT.function, + EnumScriptType.RIGHT_CLICK.function, + EnumScriptType.ATTACK.function, + EnumScriptType.START_USING_ITEM.function, + EnumScriptType.USING_ITEM.function, + EnumScriptType.STOP_USING_ITEM.function, + EnumScriptType.FINISH_USING_ITEM.function + ); + + // Linked item hooks + registerBuiltIn(CONTEXT_LINKED_ITEM, + EnumScriptType.LINKED_ITEM_BUILD.function, + EnumScriptType.LINKED_ITEM_VERSION.function, + EnumScriptType.INIT.function, + EnumScriptType.TICK.function, + EnumScriptType.TOSSED.function, + EnumScriptType.PICKEDUP.function, + EnumScriptType.SPAWN.function, + EnumScriptType.INTERACT.function, + EnumScriptType.RIGHT_CLICK.function, + EnumScriptType.ATTACK.function, + EnumScriptType.START_USING_ITEM.function, + EnumScriptType.USING_ITEM.function, + EnumScriptType.STOP_USING_ITEM.function, + EnumScriptType.FINISH_USING_ITEM.function + ); + + // Recipe hooks + registerBuiltIn(CONTEXT_RECIPE, + RecipeScript.ScriptType.PRE.function, + RecipeScript.ScriptType.POST.function + ); + + // Effect hooks + registerBuiltIn(CONTEXT_EFFECT, + EffectScript.ScriptType.OnEffectAdd.function, + EffectScript.ScriptType.OnEffectTick.function, + EffectScript.ScriptType.OnEffectRemove.function + ); + + // Forge hooks - just init, the rest are dynamically discovered + registerBuiltIn(CONTEXT_FORGE, + EnumScriptType.INIT.function + ); + } + + private void registerBuiltIn(String context, String... hooks) { + List list = builtInHooks.get(context); + if (list != null) { + for (String hook : hooks) { + if (!list.contains(hook)) { + list.add(hook); + } + } + } + } + + @Override + public void registerHook(String context, String functionName) { + if (context == null || functionName == null || functionName.isEmpty()) { + return; + } + + List hooks = addonHooks.get(context); + if (hooks == null) { + // Custom context - create it + hooks = new ArrayList<>(); + addonHooks.put(context, hooks); + } + + if (!hooks.contains(functionName) && !isBuiltInHook(context, functionName)) { + hooks.add(functionName); + } + } + + @Override + public void registerHooks(String functionName, String... contexts) { + if (functionName == null || functionName.isEmpty() || contexts == null) { + return; + } + + for (String context : contexts) { + registerHook(context, functionName); + } + } + + @Override + public void unregisterHook(String context, String functionName) { + if (context == null || functionName == null) { + return; + } + + List hooks = addonHooks.get(context); + if (hooks != null) { + hooks.remove(functionName); + } + } + + @Override + public void unregisterHookFromAll(String functionName) { + if (functionName == null) { + return; + } + + for (List hooks : addonHooks.values()) { + hooks.remove(functionName); + } + } + + @Override + public List getAddonHooks(String context) { + List hooks = addonHooks.get(context); + return hooks != null ? Collections.unmodifiableList(hooks) : Collections.emptyList(); + } + + @Override + public List getAllHooks(String context) { + List result = new ArrayList<>(); + + // Add built-in hooks + List builtIn = builtInHooks.get(context); + if (builtIn != null) { + result.addAll(builtIn); + } + + // Add addon hooks + List addon = addonHooks.get(context); + if (addon != null) { + for (String hook : addon) { + if (!result.contains(hook)) { + result.add(hook); + } + } + } + + return result; + } + + @Override + public boolean hasHook(String context, String functionName) { + if (context == null || functionName == null) { + return false; + } + + return isBuiltInHook(context, functionName) || isAddonHook(context, functionName); + } + + @Override + public String[] getContexts() { + return CONTEXTS.clone(); + } + + private boolean isBuiltInHook(String context, String functionName) { + List hooks = builtInHooks.get(context); + return hooks != null && hooks.contains(functionName); + } + + private boolean isAddonHook(String context, String functionName) { + List hooks = addonHooks.get(context); + return hooks != null && hooks.contains(functionName); + } + + /** + * Get built-in hooks for a context (used by GUIs for backwards compatibility). + */ + public List getBuiltInHooks(String context) { + List hooks = builtInHooks.get(context); + return hooks != null ? Collections.unmodifiableList(hooks) : Collections.emptyList(); + } +} diff --git a/src/main/java/noppes/npcs/scripted/NpcAPI.java b/src/main/java/noppes/npcs/scripted/NpcAPI.java index 79a6c2fa6..95e1e277c 100644 --- a/src/main/java/noppes/npcs/scripted/NpcAPI.java +++ b/src/main/java/noppes/npcs/scripted/NpcAPI.java @@ -72,6 +72,7 @@ import noppes.npcs.api.handler.IPartyHandler; import noppes.npcs.api.handler.IProfileHandler; import noppes.npcs.api.handler.IQuestHandler; import noppes.npcs.api.handler.IRecipeHandler; +import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.api.handler.ITransportHandler; import noppes.npcs.api.handler.data.IAnimation; import noppes.npcs.api.handler.data.IFrame; @@ -93,6 +94,7 @@ import noppes.npcs.controllers.PartyController; import noppes.npcs.controllers.QuestController; import noppes.npcs.controllers.RecipeController; import noppes.npcs.controllers.ScriptController; +import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.controllers.ScriptEntityData; import noppes.npcs.controllers.ServerCloneController; import noppes.npcs.controllers.SpawnController; @@ -356,6 +358,10 @@ public class NpcAPI extends AbstractNpcAPI { return AnimationController.Instance; } + public IScriptHookHandler getScriptHooks() { + return ScriptHookController.Instance; + } + @Override public String[] getAllBiomeNames() { List biomes = new ArrayList<>();