diff --git a/.gitignore b/.gitignore index f24532312..ed907b3d2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ /out/ /build/ /eclipse/ +/gradle-plugins/ .classpath .project /bin/ diff --git a/src/main/java/kamkeel/npcs/network/PacketUtil.java b/src/main/java/kamkeel/npcs/network/PacketUtil.java index cb2881eb8..9235dc1f7 100644 --- a/src/main/java/kamkeel/npcs/network/PacketUtil.java +++ b/src/main/java/kamkeel/npcs/network/PacketUtil.java @@ -251,8 +251,8 @@ public class PacketUtil { data.getScripts().add(new ScriptContainer(data)); } NBTTagCompound tabCompound = ByteBufUtils.readNBT(buffer); - ScriptContainer script = new ScriptContainer(data); - script.readFromNBT(tabCompound); + // Use factory method to create correct script unit type based on NBT + IScriptUnit script = IScriptUnit.createFromNBT(tabCompound, data); data.getScripts().set(tab, script); } else { NBTTagCompound compound = ByteBufUtils.readNBT(buffer); diff --git a/src/main/java/noppes/npcs/EventHooks.java b/src/main/java/noppes/npcs/EventHooks.java index 0dfac34ff..a0c3d2b57 100644 --- a/src/main/java/noppes/npcs/EventHooks.java +++ b/src/main/java/noppes/npcs/EventHooks.java @@ -40,7 +40,6 @@ import noppes.npcs.controllers.ScriptController; import noppes.npcs.controllers.data.Dialog; import noppes.npcs.controllers.data.EffectScript; import noppes.npcs.controllers.data.ForgeDataScript; -import noppes.npcs.controllers.data.INpcScriptHandler; import noppes.npcs.controllers.data.IScriptBlockHandler; import noppes.npcs.controllers.data.IScriptHandler; import noppes.npcs.controllers.data.Party; @@ -85,7 +84,7 @@ public class EventHooks { } public static void onScriptItemInit(IItemCustomizable item) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); if (handler != null && !handler.isClient()) { ItemEvent.InitEvent event = new ItemEvent.InitEvent(item); handler.callScript(EnumScriptType.INIT, event); @@ -94,7 +93,7 @@ public class EventHooks { } public static void onScriptItemUpdate(IItemCustomizable item, EntityLivingBase player) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); if (handler != null && !handler.isClient()) { ItemEvent.UpdateEvent event = new ItemEvent.UpdateEvent(item, NpcAPI.Instance().getIEntity(player)); handler.callScript(EnumScriptType.TICK, event); @@ -103,7 +102,7 @@ public class EventHooks { } public static boolean onScriptItemTossed(IItemCustomizable item, EntityPlayer player, EntityItem entity) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); ItemEvent.TossedEvent event = new ItemEvent.TossedEvent(item, (IPlayer) NpcAPI.Instance().getIEntity(player), NpcAPI.Instance().getIEntity(entity)); if (handler != null) { handler.callScript(EnumScriptType.TOSSED, event); @@ -112,7 +111,7 @@ public class EventHooks { } public static boolean onScriptItemPickedUp(IItemCustomizable item, EntityPlayer player) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); ItemEvent.PickedUpEvent event = new ItemEvent.PickedUpEvent(item, (IPlayer) NpcAPI.Instance().getIEntity(player)); if (handler != null) { handler.callScript(EnumScriptType.PICKEDUP, event); @@ -121,7 +120,7 @@ public class EventHooks { } public static boolean onScriptItemSpawn(IItemCustomizable item, EntityItem entity) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); ItemEvent.SpawnEvent event = new ItemEvent.SpawnEvent(item, NpcAPI.Instance().getIEntity(entity)); if (handler != null) { handler.callScript(EnumScriptType.SPAWN, event); @@ -130,7 +129,7 @@ public class EventHooks { } public static boolean onScriptItemInteract(IItemCustomizable item, noppes.npcs.scripted.event.ItemEvent.InteractEvent event) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); if (handler != null) { handler.callScript(EnumScriptType.INTERACT, event); } @@ -138,7 +137,7 @@ public class EventHooks { } public static boolean onScriptItemRightClick(IItemCustomizable item, noppes.npcs.scripted.event.ItemEvent.RightClickEvent event) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); if (handler != null) { handler.callScript(EnumScriptType.RIGHT_CLICK, event); } @@ -146,7 +145,7 @@ public class EventHooks { } public static boolean onScriptItemAttack(IItemCustomizable item, noppes.npcs.scripted.event.ItemEvent.AttackEvent event) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); if (handler != null) { handler.callScript(EnumScriptType.ATTACK, event); } @@ -154,7 +153,7 @@ public class EventHooks { } public static boolean onStartUsingCustomItem(IItemCustomizable item, IPlayer player, int duration) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); ItemEvent.StartUsingItem event = new ItemEvent.StartUsingItem(item, player, duration); if (handler != null) { handler.callScript(EnumScriptType.START_USING_ITEM, event); @@ -163,7 +162,7 @@ public class EventHooks { } public static boolean onUsingCustomItem(IItemCustomizable item, IPlayer player, int duration) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); ItemEvent.UsingItem event = new ItemEvent.UsingItem(item, player, duration); if (handler != null) { handler.callScript(EnumScriptType.USING_ITEM, event); @@ -172,7 +171,7 @@ public class EventHooks { } public static boolean onStopUsingCustomItem(IItemCustomizable item, IPlayer player, int duration) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); ItemEvent.StopUsingItem event = new ItemEvent.StopUsingItem(item, player, duration); if (handler != null) { handler.callScript(EnumScriptType.STOP_USING_ITEM, event); @@ -181,7 +180,7 @@ public class EventHooks { } public static boolean onFinishUsingCustomItem(IItemCustomizable item, IPlayer player, int duration) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); ItemEvent.FinishUsingItem event = new ItemEvent.FinishUsingItem(item, player, duration); if (handler != null) { handler.callScript(EnumScriptType.FINISH_USING_ITEM, event); @@ -190,7 +189,7 @@ public class EventHooks { } public static void onRepairCustomItem(IItemCustomizable item, IPlayer player, IItemStack left, IItemStack right, float anvilBreakChance) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); ItemEvent.RepairItem event = new ItemEvent.RepairItem(item, player, left, right, anvilBreakChance); if (handler != null) { handler.callScript(EnumScriptType.REPAIR_ITEM, event); @@ -199,7 +198,7 @@ public class EventHooks { } public static void onBreakCustomItem(IItemCustomizable item, IPlayer player) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); ItemEvent.BreakItem event = new ItemEvent.BreakItem(item, player); if (handler != null) { handler.callScript(EnumScriptType.BREAK_ITEM, event); @@ -242,7 +241,7 @@ public class EventHooks { public static void onLinkedItemVersionChange(IItemLinked item, int version, int prevVersion) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); LinkedItemEvent.VersionChangeEvent event = new LinkedItemEvent.VersionChangeEvent(item, version, prevVersion); if (handler != null) { handler.callScript(EnumScriptType.LINKED_ITEM_VERSION, event); @@ -251,7 +250,7 @@ public class EventHooks { } public static void onLinkedItemBuild(IItemLinked item) { - INpcScriptHandler handler = (INpcScriptHandler) item.getScriptHandler(); + IScriptHandler handler = (IScriptHandler) item.getScriptHandler(); LinkedItemEvent.BuildEvent event = new LinkedItemEvent.BuildEvent(item); if (handler != null) { handler.callScript(EnumScriptType.LINKED_ITEM_BUILD, event); diff --git a/src/main/java/noppes/npcs/NBTTags.java b/src/main/java/noppes/npcs/NBTTags.java index 21e751f11..fff8d1c5d 100644 --- a/src/main/java/noppes/npcs/NBTTags.java +++ b/src/main/java/noppes/npcs/NBTTags.java @@ -546,8 +546,7 @@ public class NBTTags { for (int i = 0; i < list.tagCount(); ++i) { NBTTagCompound compoundd = list.getCompoundTagAt(i); - ScriptContainer script = new ScriptContainer(handler); - script.readFromNBT(compoundd); + IScriptUnit script = IScriptUnit.createFromNBT(compoundd, handler); scripts.add(script); } @@ -559,8 +558,7 @@ public class NBTTags { for (int i = 0; i < compound.getInteger("TotalScripts"); ++i) { NBTTagCompound containerCompound = compound.getCompoundTag("Tab" + i); - ScriptContainer script = new ScriptContainer(handler); - script.readFromNBT(containerCompound); + IScriptUnit script = IScriptUnit.createFromNBT(containerCompound, handler); scripts.add(script); } diff --git a/src/main/java/noppes/npcs/blocks/tiles/TileScripted.java b/src/main/java/noppes/npcs/blocks/tiles/TileScripted.java index 2ecdb518e..7174bac6e 100644 --- a/src/main/java/noppes/npcs/blocks/tiles/TileScripted.java +++ b/src/main/java/noppes/npcs/blocks/tiles/TileScripted.java @@ -25,7 +25,6 @@ import noppes.npcs.api.IBlock; import noppes.npcs.api.block.ITextPlane; import noppes.npcs.client.renderer.blocks.BlockScriptedRenderer; import noppes.npcs.constants.EnumScriptType; -import noppes.npcs.controllers.ScriptContainer; import noppes.npcs.controllers.ScriptController; import noppes.npcs.controllers.data.IScriptBlockHandler; import noppes.npcs.controllers.data.IScriptUnit; @@ -369,9 +368,7 @@ public class TileScripted extends TileEntity implements IScriptBlockHandler { } for (IScriptUnit script : scripts) { - if (script instanceof ScriptContainer) { - ((ScriptContainer) script).run(type, event); - } + script.run(type, event); } } diff --git a/src/main/java/noppes/npcs/client/gui/GuiScript.java b/src/main/java/noppes/npcs/client/gui/GuiScript.java index a911dc88f..916a0ecd3 100644 --- a/src/main/java/noppes/npcs/client/gui/GuiScript.java +++ b/src/main/java/noppes/npcs/client/gui/GuiScript.java @@ -167,8 +167,10 @@ public class GuiScript extends GuiScriptInterface { int scrollbarOffset = activeArea.hasVerticalScrollbar() ? -8 : -2; fullscreenButton.initGui(editorX + editorWidth, editorY, scrollbarOffset); - // ==================== RIGHT PANEL BUTTONS (hidden in fullscreen) ==================== - if (!isFullscreen) { + // Set language and script context for proper syntax highlighting and autocomplete + activeArea.setLanguage(script.getLanguage()); + activeArea.setScriptContext(ScriptContext.NPC); + addButton(new GuiNpcButton(102, guiLeft + 315, guiTop + 4, 50, 20, "gui.clear")); addButton(new GuiNpcButton(101, guiLeft + 366, guiTop + 4, 50, 20, "gui.paste")); addButton(new GuiNpcButton(100, guiLeft + 315, guiTop + 25, 50, 20, "gui.copy")); @@ -182,7 +184,7 @@ public class GuiScript extends GuiScriptInterface { scroll.setList(container.scripts); addScroll(scroll); } - } + private void initSettingsView() { addLabel(new GuiNpcLabel(0, "script.console", guiLeft + 4, guiTop + 16)); @@ -316,26 +318,6 @@ public class GuiScript extends GuiScriptInterface { container.script = text; } } - - @Override - public void mouseClicked(int mouseX, int mouseY, int mouseButton) { - // Check if click is within autocomplete menu bounds and consume it if so - GuiScriptTextArea activeArea = getActiveScriptArea(); - boolean isOverAutocomplete = activeArea != null - && activeArea.isPointOnAutocompleteMenu(mouseX, mouseY); - if (isOverAutocomplete) { - activeArea.mouseClicked(mouseX, mouseY, mouseButton); - return; - } - - // Check fullscreen button when in script view - if (showScript && !isOverAutocomplete - && fullscreenButton.mouseClicked(mouseX, mouseY, mouseButton)) { - return; - } - - super.mouseClicked(mouseX, mouseY, mouseButton); - } @Override public void setGuiData(NBTTagCompound compound) { diff --git a/src/main/java/noppes/npcs/client/gui/GuiScriptList.java b/src/main/java/noppes/npcs/client/gui/GuiScriptList.java index 0d03d13cd..547f75f83 100644 --- a/src/main/java/noppes/npcs/client/gui/GuiScriptList.java +++ b/src/main/java/noppes/npcs/client/gui/GuiScriptList.java @@ -6,6 +6,7 @@ import noppes.npcs.client.gui.util.GuiNpcButton; import noppes.npcs.client.gui.util.GuiNpcLabel; import noppes.npcs.client.gui.util.SubGuiInterface; import noppes.npcs.controllers.ScriptContainer; +import noppes.npcs.controllers.data.IScriptUnit; import java.util.ArrayList; import java.util.List; @@ -13,16 +14,20 @@ import java.util.List; public class GuiScriptList extends SubGuiInterface { private GuiCustomScroll scroll1; private GuiCustomScroll scroll2; - private ScriptContainer container; + private IScriptUnit scriptUnit; private List scripts; public GuiScriptList(List scripts, ScriptContainer container) { - this.container = container; + this(scripts, (IScriptUnit) container); + } + + public GuiScriptList(List scripts, IScriptUnit scriptUnit) { + this.scriptUnit = scriptUnit; setBackground("menubg.png"); xSize = 346; ySize = 216; if (scripts == null) - scripts = new ArrayList(); + scripts = new ArrayList<>(); this.scripts = scripts; } @@ -46,10 +51,10 @@ public class GuiScriptList extends SubGuiInterface { scroll2.guiTop = guiTop + 14; this.addScroll(scroll2); addLabel(new GuiNpcLabel(2, "script.loadedScripts", guiLeft + 200, guiTop + 4)); - List temp = new ArrayList(scripts); - temp.removeAll(container.scripts); + List temp = new ArrayList<>(scripts); + temp.removeAll(scriptUnit.getExternalScripts()); scroll1.setList(temp); - scroll2.setList(container.scripts); + scroll2.setList(scriptUnit.getExternalScripts()); addButton(new GuiNpcButton(1, guiLeft + 145, guiTop + 40, 55, 20, ">")); addButton(new GuiNpcButton(2, guiLeft + 145, guiTop + 62, 55, 20, "<")); @@ -64,7 +69,7 @@ public class GuiScriptList extends SubGuiInterface { GuiNpcButton button = (GuiNpcButton) guibutton; if (button.id == 1) { if (scroll1.hasSelected()) { - container.scripts.add(scroll1.getSelected()); + scriptUnit.getExternalScripts().add(scroll1.getSelected()); scroll1.selected = -1; scroll2.selected = -1; initGui(); @@ -72,22 +77,22 @@ public class GuiScriptList extends SubGuiInterface { } if (button.id == 2) { if (scroll2.hasSelected()) { - container.scripts.remove(scroll2.getSelected()); + scriptUnit.getExternalScripts().remove(scroll2.getSelected()); scroll2.selected = -1; initGui(); } } if (button.id == 3) { - container.scripts.clear(); + scriptUnit.getExternalScripts().clear(); for (String script : scripts) { - container.scripts.add(script); + scriptUnit.getExternalScripts().add(script); } scroll1.selected = -1; scroll2.selected = -1; initGui(); } if (button.id == 4) { - container.scripts.clear(); + scriptUnit.getExternalScripts().clear(); scroll1.selected = -1; scroll2.selected = -1; initGui(); diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java b/src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java index b8d222438..2f609b205 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java @@ -1,5 +1,6 @@ package noppes.npcs.client.gui.script; + import noppes.npcs.janino.JaninoScript; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.*; 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 8b72bb145..e0ad70596 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiNPCEventScripts.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiNPCEventScripts.java @@ -35,8 +35,8 @@ public class GuiNPCEventScripts extends GuiScriptInterface { super.setGuiData(compound); } else { int tab = compound.getInteger("Tab"); - ScriptContainer container = new ScriptContainer(script); - container.readFromNBT(compound.getCompoundTag("Script")); + NBTTagCompound scriptCompound = compound.getCompoundTag("Script"); + IScriptUnit container = IScriptUnit.createFromNBT(scriptCompound, script); if (script.getScripts().isEmpty()) { for (int i = 0; i < compound.getInteger("TotalScripts"); i++) { script.getScripts().add(new ScriptContainer(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 27e2f8433..71bc73d7d 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptAllNPCs.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptAllNPCs.java @@ -33,8 +33,8 @@ public class GuiScriptAllNPCs extends GuiScriptInterface { super.setGuiData(compound); } else { int tab = compound.getInteger("Tab"); - ScriptContainer container = new ScriptContainer(script); - container.readFromNBT(compound.getCompoundTag("Script")); + NBTTagCompound scriptCompound = compound.getCompoundTag("Script"); + IScriptUnit container = IScriptUnit.createFromNBT(scriptCompound, script); if (script.getScripts().isEmpty()) { for (int i = 0; i < compound.getInteger("TotalScripts"); i++) { script.getScripts().add(new ScriptContainer(script)); 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 b7d6e8674..e50b31ade 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptEffect.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptEffect.java @@ -9,6 +9,7 @@ import noppes.npcs.controllers.ScriptContainer; import noppes.npcs.controllers.ScriptHookController; import noppes.npcs.controllers.data.CustomEffect; import noppes.npcs.controllers.data.EffectScript; +import noppes.npcs.controllers.data.IScriptUnit; import java.util.ArrayList; @@ -35,7 +36,7 @@ public class GuiScriptEffect extends GuiScriptInterface { return ScriptContext.GLOBAL; } - protected void setHandlerContainer(ScriptContainer container) { + protected void setHandlerContainer(IScriptUnit container) { this.scriptHandler.container = container; } @@ -52,4 +53,4 @@ public class GuiScriptEffect extends GuiScriptInterface { public void save() { saveWithPackets(); } -} +} \ No newline at end of file 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 d4aa8ade7..59333eee4 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptForge.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptForge.java @@ -88,8 +88,8 @@ public class GuiScriptForge extends GuiScriptInterface { super.setGuiData(compound); } else { int tab = compound.getInteger("Tab"); - ScriptContainer container = new ScriptContainer(script); - container.readFromNBT(compound.getCompoundTag("Script")); + NBTTagCompound scriptCompound = compound.getCompoundTag("Script"); + IScriptUnit container = IScriptUnit.createFromNBT(scriptCompound, script); if (script.getScripts().isEmpty()) { for (int i = 0; i < compound.getInteger("TotalScripts"); i++) { script.getScripts().add(new ScriptContainer(script)); diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiScriptInterface.java b/src/main/java/noppes/npcs/client/gui/script/GuiScriptInterface.java index 0f37c174b..3e16377f4 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptInterface.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptInterface.java @@ -3,6 +3,7 @@ package noppes.npcs.client.gui.script; import net.minecraft.client.gui.*; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.StatCollector; import noppes.npcs.NoppesStringUtils; import noppes.npcs.client.NoppesUtil; @@ -28,6 +29,7 @@ import noppes.npcs.controllers.data.IScriptHandler; import noppes.npcs.controllers.data.IScriptUnit; import noppes.npcs.scripted.item.ScriptCustomItem; import org.lwjgl.opengl.Display; +import org.lwjgl.opengl.GL11; import java.util.ArrayList; import java.util.Date; @@ -219,7 +221,10 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb // Set the scripting language for proper syntax highlighting // Use the container's language if available, otherwise fall back to handler's language String language = (container != null) ? container.getLanguage() : this.handler.getLanguage(); - activeArea.setLanguage(language); + activeArea.setLanguage(language); + + // Set the script context for context-aware hook autocomplete + activeArea.setScriptContext(getScriptContext()); // Set the script context for context-aware hook autocomplete activeArea.setScriptContext(getScriptContext()); @@ -302,25 +307,19 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { super.drawScreen(mouseX, mouseY, partialTicks); + + // Draw fullscreen button on top of everything when on script editor tab + if (this.activeTab > 0) { + fullscreenButton.draw(mouseX, mouseY); + } } // ==================== MOUSE HANDLING ==================== @Override public void mouseClicked(int mouseX, int mouseY, int mouseButton) { - // Check if click is within autocomplete menu bounds and consume it if so - GuiScriptTextArea activeArea = getActiveScriptArea(); - boolean isOverAutocomplete = activeArea != null - && activeArea.isPointOnAutocompleteMenu(mouseX, mouseY); - if (isOverAutocomplete) { - activeArea.mouseClicked(mouseX, mouseY, mouseButton); - return; - } - // Check fullscreen button first when on script editor tab - // BUT only if autocomplete is not visible (don't let clicks pass through autocomplete menu) - if (this.activeTab > 0 && !isOverAutocomplete - && fullscreenButton.mouseClicked(mouseX, mouseY, mouseButton)) { + if (this.activeTab > 0 && fullscreenButton.mouseClicked(mouseX, mouseY, mouseButton)) { return; } @@ -333,10 +332,17 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb public void customScrollClicked(int i, int j, int k, GuiCustomScroll scroll) { String hook = scroll.getSelected(); if (previousHookClicked.equals(hook)) { + IScriptUnit container = getCurrentContainer(); + if (container == null) + return; + String addString = ""; if (!this.getTextField(2).getText().isEmpty()) addString += "\n"; - addString += "function " + hook + "(event) {\n \n}\n"; + + // Generate the appropriate stub based on language + // hook is already the proper method name from EnumScriptType.function + addString += container.generateHookStub(hook, null); this.getTextField(2).setText(this.getTextField(2).getText() + addString); previousHookClicked = ""; @@ -650,8 +656,8 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb this.loadLanguagesData(compound); } else { int tab = compound.getInteger("Tab"); - ScriptContainer container = new ScriptContainer(this.handler); - container.readFromNBT(compound.getCompoundTag("Script")); + NBTTagCompound scriptCompound = compound.getCompoundTag("Script"); + IScriptUnit container = IScriptUnit.createFromNBT(scriptCompound, this.handler); this.setHandlerContainer(container); this.initGui(); } 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 6eb43722a..2a001b732 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptLinkedItem.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptLinkedItem.java @@ -1,10 +1,6 @@ package noppes.npcs.client.gui.script; import kamkeel.npcs.network.packets.request.script.item.LinkedItemScriptPacket; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiConfirmOpenLink; -import net.minecraft.client.gui.GuiYesNo; -import net.minecraft.client.gui.GuiYesNoCallback; import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.client.gui.global.GuiNPCManageLinked; @@ -12,6 +8,7 @@ import noppes.npcs.constants.EnumScriptType; import noppes.npcs.constants.ScriptContext; import noppes.npcs.controllers.ScriptContainer; import noppes.npcs.controllers.ScriptHookController; +import noppes.npcs.controllers.data.IScriptUnit; import noppes.npcs.controllers.data.LinkedItem; import noppes.npcs.controllers.data.LinkedItemScript; @@ -38,7 +35,7 @@ public class GuiScriptLinkedItem extends GuiScriptInterface { return ScriptContext.ITEM; } - protected void setHandlerContainer(ScriptContainer container) { + protected void setHandlerContainer(IScriptUnit container) { ((LinkedItemScript) handler).container = container; } 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 46d0adf35..de884b356 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptPlayers.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptPlayers.java @@ -6,10 +6,8 @@ import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.NBTTags; import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.constants.ScriptContext; -import noppes.npcs.constants.EnumScriptType; import noppes.npcs.controllers.ScriptContainer; import noppes.npcs.controllers.ScriptHookController; -import noppes.npcs.controllers.data.EffectScript; import noppes.npcs.controllers.data.IScriptUnit; import noppes.npcs.controllers.data.PlayerDataScript; @@ -38,8 +36,8 @@ public class GuiScriptPlayers extends GuiScriptInterface { super.setGuiData(compound); } else { int tab = compound.getInteger("Tab"); - ScriptContainer container = new ScriptContainer(script); - container.readFromNBT(compound.getCompoundTag("Script")); + NBTTagCompound scriptCompound = compound.getCompoundTag("Script"); + IScriptUnit container = IScriptUnit.createFromNBT(scriptCompound, script); if (script.getScripts().isEmpty()) { for (int i = 0; i < compound.getInteger("TotalScripts"); i++) { script.getScripts().add(new ScriptContainer(script)); 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 0b70a1233..176294f7e 100644 --- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptRecipe.java +++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptRecipe.java @@ -1,16 +1,13 @@ package noppes.npcs.client.gui.script; import kamkeel.npcs.network.packets.request.script.RecipeScriptPacket; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiConfirmOpenLink; -import net.minecraft.client.gui.GuiYesNo; -import net.minecraft.client.gui.GuiYesNoCallback; import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.api.handler.IScriptHookHandler; import noppes.npcs.client.gui.global.GuiNpcManageRecipes; import noppes.npcs.constants.ScriptContext; import noppes.npcs.controllers.ScriptContainer; import noppes.npcs.controllers.ScriptHookController; +import noppes.npcs.controllers.data.IScriptUnit; import noppes.npcs.controllers.data.RecipeAnvil; import noppes.npcs.controllers.data.RecipeCarpentry; import noppes.npcs.controllers.data.RecipeScript; @@ -52,7 +49,7 @@ public class GuiScriptRecipe extends GuiScriptInterface { return ScriptContext.GLOBAL; } - protected void setHandlerContainer(ScriptContainer container) { + protected void setHandlerContainer(IScriptUnit container) { ((RecipeScript) handler).container = container; } diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java index 026086a4c..ce5912154 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java @@ -559,6 +559,15 @@ public class GuiScriptTextArea extends GuiNpcTextField { public boolean fullscreen() { return GuiScriptInterface.isFullscreen; } + + public void setLanguage(String language) { + if (this.container != null) { + // this.container.setLanguage(language); + if (this.enableCodeHighlighting) { + this.container.formatCodeText(); + } + } + } // ==================== RENDERING ==================== public void drawTextBox(int xMouse, int yMouse) { if (!visible) @@ -2651,6 +2660,28 @@ public class GuiScriptTextArea extends GuiNpcTextField { return this.container != null ? this.container.getScriptContext() : ScriptContext.GLOBAL; } + /** + * Set the script context (NPC, PLAYER, BLOCK, ITEM, etc.). + * This determines which hooks and event types are available for autocomplete. + * + * @param context The script context + */ + public void setScriptContext(ScriptContext context) { + if (this.container != null) { + // this.container.setScriptContext(context); + } + } + + /** + * Get the current script context. + * + * @return The script context (NPC, PLAYER, BLOCK, ITEM, etc.) + */ + public ScriptContext getScriptContext() { + // return this.container != null ? this.container.getScriptContext() : ScriptContext.GLOBAL; + return ScriptContext.GLOBAL; + } + public void setListener(ITextChangeListener listener) { this.listener = listener; } diff --git a/src/main/java/noppes/npcs/controllers/LinkedItemController.java b/src/main/java/noppes/npcs/controllers/LinkedItemController.java index c2bc19044..48f19958b 100644 --- a/src/main/java/noppes/npcs/controllers/LinkedItemController.java +++ b/src/main/java/noppes/npcs/controllers/LinkedItemController.java @@ -7,7 +7,7 @@ import noppes.npcs.CustomNpcs; import noppes.npcs.LogWriter; import noppes.npcs.api.handler.data.ILinkedItem; import noppes.npcs.api.item.IItemStack; -import noppes.npcs.controllers.data.INpcScriptHandler; +import noppes.npcs.controllers.data.IScriptHandler; import noppes.npcs.controllers.data.LinkedItem; import noppes.npcs.controllers.data.LinkedItemScript; import noppes.npcs.util.NBTJsonUtil; @@ -90,7 +90,7 @@ public class LinkedItemController { return this.linkedItems.containsValue(linkedItem); } - public INpcScriptHandler getScriptHandler(int id) { + public IScriptHandler getScriptHandler(int id) { return this.linkedItemsScripts.get(id); } diff --git a/src/main/java/noppes/npcs/controllers/ScriptContainer.java b/src/main/java/noppes/npcs/controllers/ScriptContainer.java index f8649ac47..498b4fbbd 100644 --- a/src/main/java/noppes/npcs/controllers/ScriptContainer.java +++ b/src/main/java/noppes/npcs/controllers/ScriptContainer.java @@ -70,6 +70,7 @@ public class ScriptContainer implements IScriptUnit { } public NBTTagCompound writeToNBT(NBTTagCompound compound) { + compound.setString(IScriptUnit.NBT_TYPE_KEY, IScriptUnit.TYPE_ECMASCRIPT); if (this.script.length() < 65535) { compound.setString("Script", this.script); } else { diff --git a/src/main/java/noppes/npcs/controllers/data/DataScript.java b/src/main/java/noppes/npcs/controllers/data/DataScript.java index 45ba9a966..6e07223a8 100644 --- a/src/main/java/noppes/npcs/controllers/data/DataScript.java +++ b/src/main/java/noppes/npcs/controllers/data/DataScript.java @@ -19,6 +19,7 @@ import noppes.npcs.constants.EnumScriptType; import noppes.npcs.controllers.ScriptContainer; import noppes.npcs.controllers.ScriptController; import noppes.npcs.entity.EntityNPCInterface; +import noppes.npcs.janino.impl.JaninoNpcScript; import noppes.npcs.scripted.NpcAPI; import noppes.npcs.scripted.ScriptWorld; import noppes.npcs.scripted.constants.EntityType; @@ -35,7 +36,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; -public class DataScript implements INpcScriptHandler { +public class DataScript implements IScriptHandler { public List eventScripts = new ArrayList<>(); private HashMap scripts = new HashMap<>(); @@ -153,9 +154,7 @@ public class DataScript implements INpcScriptHandler { } for (IScriptUnit script : this.eventScripts) { - if (script instanceof ScriptContainer) { - ((ScriptContainer) script).run(type, event); - } + script.run(type, event); } ScriptContainer script = scripts.get(type); @@ -314,4 +313,8 @@ public class DataScript implements INpcScriptHandler { public Collection getNPCScripts() { return this.scripts.values(); } + @Override + public IScriptUnit createJaninoScriptUnit() { + return new JaninoNpcScript(); + } } diff --git a/src/main/java/noppes/npcs/controllers/data/EffectScript.java b/src/main/java/noppes/npcs/controllers/data/EffectScript.java index 497b46421..dcd497fc8 100644 --- a/src/main/java/noppes/npcs/controllers/data/EffectScript.java +++ b/src/main/java/noppes/npcs/controllers/data/EffectScript.java @@ -8,7 +8,6 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.common.util.Constants; import noppes.npcs.config.ConfigScript; import noppes.npcs.constants.EnumScriptType; -import noppes.npcs.controllers.ScriptContainer; import noppes.npcs.controllers.ScriptController; import noppes.npcs.scripted.event.player.PlayerEvent; @@ -19,7 +18,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; -public class EffectScript implements INpcScriptHandler { +public class EffectScript implements IScriptHandler { public IScriptUnit container; public String scriptLanguage = "ECMAScript"; public boolean enabled = false; @@ -39,8 +38,7 @@ public class EffectScript implements INpcScriptHandler { enabled = compound.getBoolean("ScriptEnabled"); if (compound.hasKey("ScriptContent", Constants.NBT.TAG_COMPOUND)) { - container = new ScriptContainer(this); - container.readFromNBT(compound.getCompoundTag("ScriptContent")); + container = IScriptUnit.createFromNBT(compound.getCompoundTag("ScriptContent"), this); } return this; } @@ -63,8 +61,9 @@ public class EffectScript implements INpcScriptHandler { if (!this.isEnabled()) { return; } - if (container instanceof ScriptContainer) - ((ScriptContainer) container).run(s, event); + if (container != null) { + container.run(s, event); + } } @Override @@ -142,9 +141,7 @@ public class EffectScript implements INpcScriptHandler { if (tab == 0) { NBTTagCompound tabCompound = ByteBufUtils.readNBT(buffer); - ScriptContainer script = new ScriptContainer(this); - script.readFromNBT(tabCompound); - this.container = script; + this.container = IScriptUnit.createFromNBT(tabCompound, this); } else { NBTTagCompound compound = ByteBufUtils.readNBT(buffer); this.setLanguage(compound.getString("ScriptLanguage")); diff --git a/src/main/java/noppes/npcs/controllers/data/ForgeDataScript.java b/src/main/java/noppes/npcs/controllers/data/ForgeDataScript.java index d38342f0e..043e56efe 100644 --- a/src/main/java/noppes/npcs/controllers/data/ForgeDataScript.java +++ b/src/main/java/noppes/npcs/controllers/data/ForgeDataScript.java @@ -15,7 +15,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; -public class ForgeDataScript implements INpcScriptHandler { +public class ForgeDataScript implements IScriptHandler { private List scripts = new ArrayList<>(); private String scriptLanguage = "ECMAScript"; public long lastInited = -1L; @@ -78,14 +78,9 @@ public class ForgeDataScript implements INpcScriptHandler { } for (IScriptUnit script : this.scripts) { - if (script == null || !script.hasCode()) + if (script == null || script.hasErrored() || !script.hasCode()) continue; - if (script instanceof ScriptContainer) { - ScriptContainer container = (ScriptContainer) script; - if (container.errored) - continue; - container.run(type, event); - } + script.run(type, event); } } } diff --git a/src/main/java/noppes/npcs/controllers/data/GlobalNPCDataScript.java b/src/main/java/noppes/npcs/controllers/data/GlobalNPCDataScript.java index f21818136..c4dc15913 100644 --- a/src/main/java/noppes/npcs/controllers/data/GlobalNPCDataScript.java +++ b/src/main/java/noppes/npcs/controllers/data/GlobalNPCDataScript.java @@ -26,7 +26,7 @@ import java.util.OptionalInt; import java.util.OptionalLong; import java.util.TreeMap; -public class GlobalNPCDataScript implements INpcScriptHandler { +public class GlobalNPCDataScript implements IScriptHandler { public List scripts = new ArrayList<>(); public String scriptLanguage = "ECMAScript"; private EntityNPCInterface npc; @@ -94,14 +94,9 @@ public class GlobalNPCDataScript implements INpcScriptHandler { } for (IScriptUnit script : this.scripts) { - if (script == null || !script.hasCode()) + if (script == null || script.hasErrored() || !script.hasCode()) continue; - if (script instanceof ScriptContainer) { - ScriptContainer container = (ScriptContainer) script; - if (container.errored) - continue; - container.run(hookName, event); - } + script.run(hookName, event); } } } diff --git a/src/main/java/noppes/npcs/controllers/data/INpcScriptHandler.java b/src/main/java/noppes/npcs/controllers/data/INpcScriptHandler.java index 508836d1c..82119a6d4 100644 --- a/src/main/java/noppes/npcs/controllers/data/INpcScriptHandler.java +++ b/src/main/java/noppes/npcs/controllers/data/INpcScriptHandler.java @@ -1,8 +1,7 @@ package noppes.npcs.controllers.data; -import cpw.mods.fml.common.eventhandler.Event; -import noppes.npcs.constants.EnumScriptType; - public interface INpcScriptHandler extends IScriptHandler { - void callScript(EnumScriptType var1, Event var2); + // This interface is now empty - callScript methods moved to IScriptHandler + // Kept for backward compatibility + } diff --git a/src/main/java/noppes/npcs/controllers/data/IScriptBlockHandler.java b/src/main/java/noppes/npcs/controllers/data/IScriptBlockHandler.java index c0445594e..f39b87112 100644 --- a/src/main/java/noppes/npcs/controllers/data/IScriptBlockHandler.java +++ b/src/main/java/noppes/npcs/controllers/data/IScriptBlockHandler.java @@ -2,7 +2,7 @@ package noppes.npcs.controllers.data; import noppes.npcs.api.IBlock; -public interface IScriptBlockHandler extends INpcScriptHandler { +public interface IScriptBlockHandler extends IScriptHandler { IBlock getBlock(); } diff --git a/src/main/java/noppes/npcs/controllers/data/IScriptHandler.java b/src/main/java/noppes/npcs/controllers/data/IScriptHandler.java index 2aa9c1db5..6b551feb9 100644 --- a/src/main/java/noppes/npcs/controllers/data/IScriptHandler.java +++ b/src/main/java/noppes/npcs/controllers/data/IScriptHandler.java @@ -1,11 +1,14 @@ package noppes.npcs.controllers.data; import cpw.mods.fml.common.eventhandler.Event; +import noppes.npcs.constants.EnumScriptType; import java.util.List; import java.util.Map; public interface IScriptHandler { + void callScript(EnumScriptType type, Event event); + void callScript(String hookName, Event event); boolean isClient(); diff --git a/src/main/java/noppes/npcs/controllers/data/IScriptUnit.java b/src/main/java/noppes/npcs/controllers/data/IScriptUnit.java index d8d280be0..392901ede 100644 --- a/src/main/java/noppes/npcs/controllers/data/IScriptUnit.java +++ b/src/main/java/noppes/npcs/controllers/data/IScriptUnit.java @@ -1,6 +1,9 @@ package noppes.npcs.controllers.data; +import cpw.mods.fml.common.eventhandler.Event; import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.constants.EnumScriptType; +import noppes.npcs.controllers.ScriptContainer; import java.util.List; import java.util.Map; @@ -13,6 +16,39 @@ import java.util.TreeMap; */ public interface IScriptUnit { + // NBT type identifiers + String NBT_TYPE_KEY = "ScriptUnitType"; + String TYPE_ECMASCRIPT = "ECMAScript"; + String TYPE_JANINO = "Janino"; + + /** + * Create an IScriptUnit from NBT data. + * Uses the "ScriptUnitType" tag to determine which implementation to create. + * + * @param compound The NBT data + * @param handler The script handler (used for ScriptContainer) + * @return A ScriptContainer or JaninoScript based on the NBT type + */ + static IScriptUnit createFromNBT(NBTTagCompound compound, IScriptHandler handler) { + String type = compound.getString(NBT_TYPE_KEY); + IScriptUnit unit; + + if (TYPE_JANINO.equals(type)) { + // Create appropriate JaninoScript based on handler + unit = handler.createJaninoScriptUnit(); + if (unit == null) { + // Fallback to ScriptContainer if handler doesn't support Janino + unit = new ScriptContainer(handler); + } + } else { + // Default to ScriptContainer for ECMAScript or missing type + unit = new ScriptContainer(handler); + } + + unit.readFromNBT(compound); + return unit; + } + // ==================== SCRIPT CONTENT ==================== /** @@ -114,4 +150,26 @@ public interface IScriptUnit { * Set the error state of this script unit. */ void setErrored(boolean errored); + + // ==================== EXECUTION ==================== + + /** + * Execute this script unit for the given hook type and event. + * For ScriptContainer: calls run(EnumScriptType, Event) + * For JaninoScript: calls callByHookType(EnumScriptType, Event) + * + * @param type The script hook type + * @param event The event object + */ + void run(EnumScriptType type, Event event); + + /** + * Execute this script unit for the given hook name and event. + * For ScriptContainer: calls run(String, Event) + * For JaninoScript: converts hookName to EnumScriptType and calls callByHookType + * + * @param hookName The hook name (e.g., "init", "interact") + * @param event The event object + */ + void run(String hookName, Object event); } diff --git a/src/main/java/noppes/npcs/controllers/data/LinkedItemScript.java b/src/main/java/noppes/npcs/controllers/data/LinkedItemScript.java index 18df07229..a2f3a3025 100644 --- a/src/main/java/noppes/npcs/controllers/data/LinkedItemScript.java +++ b/src/main/java/noppes/npcs/controllers/data/LinkedItemScript.java @@ -8,7 +8,6 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.common.util.Constants; import noppes.npcs.config.ConfigScript; import noppes.npcs.constants.EnumScriptType; -import noppes.npcs.controllers.ScriptContainer; import noppes.npcs.controllers.ScriptController; import java.io.IOException; @@ -18,7 +17,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; -public class LinkedItemScript implements INpcScriptHandler { +public class LinkedItemScript implements IScriptHandler { public IScriptUnit container; public String scriptLanguage = "ECMAScript"; public boolean enabled = false; @@ -37,8 +36,7 @@ public class LinkedItemScript implements INpcScriptHandler { enabled = compound.getBoolean("ScriptEnabled"); if (compound.hasKey("ScriptContent", Constants.NBT.TAG_COMPOUND)) { - container = new ScriptContainer(this); - container.readFromNBT(compound.getCompoundTag("ScriptContent")); + container = IScriptUnit.createFromNBT(compound.getCompoundTag("ScriptContent"), this); } return this; } @@ -57,8 +55,9 @@ public class LinkedItemScript implements INpcScriptHandler { if (!this.isEnabled()) { return; } - if (container instanceof ScriptContainer) - ((ScriptContainer) container).run(s, event); + if (container != null) { + container.run(s, event); + } } @Override @@ -136,9 +135,7 @@ public class LinkedItemScript implements INpcScriptHandler { if (tab == 0) { NBTTagCompound tabCompound = ByteBufUtils.readNBT(buffer); - ScriptContainer script = new ScriptContainer(this); - script.readFromNBT(tabCompound); - this.container = script; + this.container = IScriptUnit.createFromNBT(tabCompound, this); } else { NBTTagCompound compound = ByteBufUtils.readNBT(buffer); this.setLanguage(compound.getString("ScriptLanguage")); diff --git a/src/main/java/noppes/npcs/controllers/data/PlayerDataScript.java b/src/main/java/noppes/npcs/controllers/data/PlayerDataScript.java index 5d2eee9f9..c8dd007f7 100644 --- a/src/main/java/noppes/npcs/controllers/data/PlayerDataScript.java +++ b/src/main/java/noppes/npcs/controllers/data/PlayerDataScript.java @@ -30,7 +30,7 @@ import java.util.OptionalInt; import java.util.OptionalLong; import java.util.TreeMap; -public class PlayerDataScript implements INpcScriptHandler { +public class PlayerDataScript implements IScriptHandler { public List scripts = new ArrayList<>(); public String scriptLanguage = "ECMAScript"; private EntityPlayer player; @@ -105,11 +105,10 @@ public class PlayerDataScript implements INpcScriptHandler { if (player != null) { scripts.clear(); for (IScriptUnit script : ScriptController.Instance.playerScripts.scripts) { - if (script instanceof ScriptContainer) { - ScriptContainer s = new ScriptContainer(this); - s.readFromNBT(((ScriptContainer) script).writeToNBT(new NBTTagCompound())); - scripts.add(s); - } + // Clone the script unit by writing to NBT and reading back with factory + NBTTagCompound nbt = script.writeToNBT(new NBTTagCompound()); + IScriptUnit cloned = IScriptUnit.createFromNBT(nbt, this); + scripts.add(cloned); } } lastPlayerUpdate = ScriptController.Instance.lastPlayerUpdate; @@ -122,18 +121,15 @@ public class PlayerDataScript implements INpcScriptHandler { IScriptUnit script = scripts.get(i); if (errored.contains(i)) continue; - if (script instanceof ScriptContainer) { - ScriptContainer container = (ScriptContainer) script; - container.run(hookName, event); - if (container.errored) { - errored.add(i); - } - for (Entry entry : container.console.entrySet()) { - if (!console.containsKey(entry.getKey())) - console.put(entry.getKey(), " tab " + (i + 1) + ":\n" + entry.getValue()); - } - container.console.clear(); + script.run(hookName, event); + if (script.hasErrored()) { + errored.add(i); } + for (Entry entry : script.getConsole().entrySet()) { + if (!console.containsKey(entry.getKey())) + console.put(entry.getKey(), " tab " + (i + 1) + ":\n" + entry.getValue()); + } + script.clearConsole(); } } else { if (ScriptController.Instance.lastLoaded > this.lastInited || ScriptController.Instance.lastPlayerUpdate > this.lastPlayerUpdate) { @@ -152,12 +148,9 @@ public class PlayerDataScript implements INpcScriptHandler { } for (IScriptUnit script : this.scripts) { - if (script == null || script.hasErrored()|| !script.hasCode()) + if (script == null || script.hasErrored() || !script.hasCode()) continue; - if (script instanceof ScriptContainer) { - ScriptContainer container = (ScriptContainer) script; - container.run(hookName, event); - } + script.run(hookName, event); } } } diff --git a/src/main/java/noppes/npcs/controllers/data/RecipeScript.java b/src/main/java/noppes/npcs/controllers/data/RecipeScript.java index b42595cf5..ee1b32c08 100644 --- a/src/main/java/noppes/npcs/controllers/data/RecipeScript.java +++ b/src/main/java/noppes/npcs/controllers/data/RecipeScript.java @@ -8,7 +8,6 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.common.util.Constants; import noppes.npcs.config.ConfigScript; import noppes.npcs.constants.EnumScriptType; -import noppes.npcs.controllers.ScriptContainer; import noppes.npcs.controllers.ScriptController; import java.io.IOException; @@ -18,7 +17,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; -public class RecipeScript implements INpcScriptHandler { +public class RecipeScript implements IScriptHandler { public IScriptUnit container; public String scriptLanguage = "ECMAScript"; public boolean enabled = false; @@ -35,8 +34,7 @@ public class RecipeScript implements INpcScriptHandler { scriptLanguage = compound.getString("ScriptLanguage"); enabled = compound.getBoolean("ScriptEnabled"); if (compound.hasKey("ScriptContent", Constants.NBT.TAG_COMPOUND)) { - container = new ScriptContainer(this); - container.readFromNBT(compound.getCompoundTag("ScriptContent")); + container = IScriptUnit.createFromNBT(compound.getCompoundTag("ScriptContent"), this); } return this; } @@ -54,8 +52,9 @@ public class RecipeScript implements INpcScriptHandler { public void callScript(String s, Event event) { if (!this.isEnabled()) return; - if (container instanceof ScriptContainer) - ((ScriptContainer) container).run(s, event); + if (container != null) { + container.run(s, event); + } } @Override @@ -131,9 +130,7 @@ public class RecipeScript implements INpcScriptHandler { this.container = null; if (tab == 0) { NBTTagCompound tabCompound = ByteBufUtils.readNBT(buffer); - ScriptContainer script = new ScriptContainer(this); - script.readFromNBT(tabCompound); - this.container = script; + this.container = IScriptUnit.createFromNBT(tabCompound, this); } else { NBTTagCompound compound = ByteBufUtils.readNBT(buffer); this.setLanguage(compound.getString("ScriptLanguage")); diff --git a/src/main/java/noppes/npcs/janino/JaninoScript.java b/src/main/java/noppes/npcs/janino/JaninoScript.java index 5fb02a46e..0f9d5c9f1 100644 --- a/src/main/java/noppes/npcs/janino/JaninoScript.java +++ b/src/main/java/noppes/npcs/janino/JaninoScript.java @@ -1,14 +1,18 @@ package noppes.npcs.janino; import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.Event; import io.github.somehussar.janinoloader.api.script.IScriptBodyBuilder; import io.github.somehussar.janinoloader.api.script.IScriptClassBody; import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.CustomNpcs; import noppes.npcs.NBTTags; import noppes.npcs.config.ConfigScript; +import noppes.npcs.constants.EnumScriptType; import noppes.npcs.controllers.ScriptController; import noppes.npcs.controllers.data.IScriptUnit; +import noppes.npcs.janino.annotations.ParamName; +import noppes.npcs.janino.annotations.ScriptHook; import org.codehaus.commons.compiler.InternalCompilerException; import org.codehaus.commons.compiler.Sandbox; @@ -46,6 +50,14 @@ public abstract class JaninoScript implements IScriptUnit { public final IScriptBodyBuilder builder; protected IScriptClassBody scriptBody; + private boolean hooksInitialized = false; + // Hook list for GUI display + private List hookList = new ArrayList<>(); + // Map from display name (with parameters if overloaded) to Method + private Map hookMap = new HashMap<>(); + // Map from EnumScriptType to Method for OLD tab-based script system + private Map hookTypeMap = new HashMap<>(); + protected JaninoScript(Class type, Consumer> buildSettings) { this.type = type; this.builder = IScriptBodyBuilder @@ -57,6 +69,9 @@ public abstract class JaninoScript implements IScriptUnit { sandbox = new Sandbox(permissions); this.scriptBody = builder.build(); + + // Build hook type map from @ScriptHook annotations + initializeHookTypeMap(); } protected T getUnsafe() { @@ -189,9 +204,85 @@ public abstract class JaninoScript implements IScriptUnit { sb.append(code).append("\n"); } } - + + /** + * Scans the Functions interface for @ScriptHook annotations and builds the hookTypeMap. + * This allows direct method invocation by EnumScriptType without switch statements. + */ + private void initializeHookTypeMap() { + for (Method method : type.getDeclaredMethods()) { + ScriptHook annotation = method.getAnnotation(ScriptHook.class); + if (annotation != null) { + for (EnumScriptType hookType : annotation.value()) { + hookTypeMap.put(hookType, method); + } + } + } + } + + /** + * Call a hook method by its EnumScriptType. + * Used by the OLD tab-based script system to execute hooks directly. + * + * @param hookType The script type/hook to execute + * @param event The event object to pass to the hook method + */ + public void callByHookType(EnumScriptType hookType, Object event) { + Method method = hookTypeMap.get(hookType); + if (method == null) { + // Hook not implemented or not annotated + return; + } + + ensureCompiled(); + T t = getUnsafe(); + if (t == null) + return; + + try { + sandbox.confine((PrivilegedAction) () -> { + try { + method.invoke(t, event); + } catch (Exception e) { + appendConsole("Error calling hook " + hookType.name() + ": " + e.getMessage()); + } + return null; + }); + } catch (Exception e) { + appendConsole("Runtime Error in hook " + hookType.name() + ": " + e.getMessage()); + } + } + // ==================== IScriptUnit IMPLEMENTATION ==================== + /** + * Execute this script unit for the given hook type and event. + * Implementation of IScriptUnit.run(EnumScriptType, Event) + * + * @param type The script hook type + * @param event The event object + */ + @Override + public void run(EnumScriptType type, Event event) { + callByHookType(type, event); + } + + /** + * Execute this script unit for the given hook name and event. + * Implementation of IScriptUnit.run(String, Event) + * + * @param hookName The hook name (e.g., "init", "interact") + * @param event The event object + */ + @Override + public void run(String hookName, Object event) { + try { + EnumScriptType enumType = EnumScriptType.valueOfIgnoreCase(hookName); + callByHookType(enumType, event); + } catch (IllegalArgumentException ignored) { + // Hook name doesn't map to an EnumScriptType + } + } @Override public String getScript() { return this.script; @@ -257,15 +348,22 @@ public abstract class JaninoScript implements IScriptUnit { return true; return script != null && !script.isEmpty(); } - + @Override public String generateHookStub(String hookName, Object hookData) { - // If hookData is a Method, generate full Java method stub - if (hookData instanceof Method) { - return generateMethodStub((Method) hookData); + // Build hook list and map + if (!hooksInitialized) { + createHookList(); + hooksInitialized = true; } - // Fallback for simple hook names - generate basic override - return String.format("@Override\npublic void %s() {\n \n}\n", hookName); + + // Look up in hookMap (handles both simple names and overloaded display names) + Method method = hookMap.get(hookName); + if (method != null) + return generateMethodStub(method); + + // Fallback for unknown hook names - generate basic override + return String.format("public void %s() {\n \n}\n", hookName); } /** @@ -285,12 +383,22 @@ public abstract class JaninoScript implements IScriptUnit { String params = Arrays.stream(method.getParameters()) .map(p -> { String typeName = p.getType().getSimpleName(); - String baseName = Character.toLowerCase(typeName.charAt(0)) + typeName.substring(1); - int count = typeCount.getOrDefault(baseName, 0) + 1; - typeCount.put(baseName, count); + // Check for @ParamName annotation first + ParamName paramNameAnnotation = p.getAnnotation(ParamName.class); + String paramName; - String paramName = count == 1 ? baseName : baseName + (count - 1); + if (paramNameAnnotation != null) { + // Use annotated name + paramName = paramNameAnnotation.value(); + } else { + // Fall back to generated name + String baseName = Character.toLowerCase(typeName.charAt(0)) + typeName.substring(1); + int count = typeCount.getOrDefault(baseName, 0) + 1; + typeCount.put(baseName, count); + paramName = count == 1 ? baseName : baseName + (count - 1); + } + return typeName + " " + paramName; }) .collect(Collectors.joining(", ")); @@ -310,12 +418,55 @@ public abstract class JaninoScript implements IScriptUnit { body = " return null;"; } - return String.format("@Override\n%s%s %s(%s) {\n%s\n}\n", mods, returnTypeStr, name, params, body); + return String.format("%s%s %s(%s) {\n%s\n}\n", mods, returnTypeStr, name, params, body); + } + + + /** + * Create the hook list and hook map for GUI display and generation. + * Groups methods by name and creates display names with parameters for overloaded methods. + */ + private void createHookList() { + // Group all declared methods by their name + Map> grouped = Arrays.stream(type.getDeclaredMethods()) + .collect(Collectors.groupingBy(Method::getName)); + + for (Map.Entry> entry : grouped.entrySet()) { + List methods = entry.getValue(); + + // Sort overloads by parameter count (ascending) + methods.sort(Comparator.comparingInt(Method::getParameterCount)); + boolean first = true; + + for (Method m : methods) { + if (Modifier.isFinal(m.getModifiers())) + continue; // Skip final methods + + // For first (simplest) overload, use just the method name + // For additional overloads, include parameter types in display name + String displayName = first ? m.getName() : + m.getName() + "(" + Arrays.stream(m.getParameterTypes()) + .map(Class::getSimpleName) + .collect(Collectors.joining(", ")) + ")"; + + hookList.add(displayName); + hookMap.put(displayName, m); + first = false; + } + } + } + + /** + * Get the list of hook names for GUI display. + */ + public List getHookList() { + return new ArrayList<>(hookList); } @Override public NBTTagCompound writeToNBT(NBTTagCompound compound) { + compound.setString(IScriptUnit.NBT_TYPE_KEY, IScriptUnit.TYPE_JANINO); compound.setBoolean("enabled", enabled); compound.setTag("console", NBTTags.NBTLongStringMap(this.console)); compound.setTag("externalScripts", NBTTags.nbtStringList(this.externalScripts)); diff --git a/src/main/java/noppes/npcs/janino/annotations/ParamName.java b/src/main/java/noppes/npcs/janino/annotations/ParamName.java new file mode 100644 index 000000000..6b1e9ec25 --- /dev/null +++ b/src/main/java/noppes/npcs/janino/annotations/ParamName.java @@ -0,0 +1,20 @@ +package noppes.npcs.janino.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specifies the parameter name and type to use when generating method stubs. + * Applied to interface method parameters to preserve their names and types in generated code. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface ParamName { + /** The parameter name (e.g., "event") */ + String value(); + + /** The fully qualified type name (e.g., "noppes.npcs.api.event.INpcEvent.InitEvent") */ + String type() default ""; +} diff --git a/src/main/java/noppes/npcs/janino/annotations/ScriptHook.java b/src/main/java/noppes/npcs/janino/annotations/ScriptHook.java new file mode 100644 index 000000000..d4720b5d8 --- /dev/null +++ b/src/main/java/noppes/npcs/janino/annotations/ScriptHook.java @@ -0,0 +1,22 @@ +package noppes.npcs.janino.annotations; + +import noppes.npcs.constants.EnumScriptType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to mark script hook methods and associate them with their EnumScriptType. + * Used by JaninoScript to automatically build a map of hook types to methods. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface ScriptHook { + /** + * The script type(s) this method handles. + * Multiple types can be specified for methods that handle multiple hooks. + */ + EnumScriptType[] value(); +} diff --git a/src/main/java/noppes/npcs/janino/impl/JaninoNpcScript.java b/src/main/java/noppes/npcs/janino/impl/JaninoNpcScript.java new file mode 100644 index 000000000..b41e2aac8 --- /dev/null +++ b/src/main/java/noppes/npcs/janino/impl/JaninoNpcScript.java @@ -0,0 +1,120 @@ +package noppes.npcs.janino.impl; + +import noppes.npcs.api.event.IAbilityEvent; +import noppes.npcs.api.event.INpcEvent; +import noppes.npcs.api.event.IProjectileEvent; +import noppes.npcs.constants.EnumScriptType; +import noppes.npcs.janino.JaninoScript; +import noppes.npcs.janino.annotations.ParamName; +import noppes.npcs.janino.annotations.ScriptHook; + +/** + * Janino (Java) script implementation for NPC events. + * This allows NPCs to use compiled Java code instead of ECMAScript. + */ +public class JaninoNpcScript extends JaninoScript { + + public JaninoNpcScript() { + super(Functions.class, (builder) -> builder + .setDefaultImports( + "noppes.npcs.api.*", + "noppes.npcs.api.entity.*", + "noppes.npcs.api.event.*", + "noppes.npcs.api.handler.*", + "noppes.npcs.api.handler.data.*", + "noppes.npcs.api.item.*", + "noppes.npcs.api.ability.*" + ) + ); + } + + /** + * Interface defining the hook methods available for NPC scripts. + * Each method corresponds to an NPC event from ScriptHookController CONTEXT_NPC. + * Methods are annotated with @ScriptHook to map them to their EnumScriptType. + */ + public interface Functions { + // Core lifecycle events + @ScriptHook(EnumScriptType.INIT) + default void init(@ParamName("event") INpcEvent.InitEvent event) {} + + @ScriptHook(EnumScriptType.TICK) + default void tick(@ParamName("event") INpcEvent.UpdateEvent event) {} + + + // Interaction events + @ScriptHook(EnumScriptType.INTERACT) + default void interact(@ParamName("event") INpcEvent.InteractEvent event) {} + + @ScriptHook(EnumScriptType.DIALOG) + default void dialog(@ParamName("event") INpcEvent.DialogEvent event) {} + + @ScriptHook(EnumScriptType.DIALOG_CLOSE) + default void dialogClose(@ParamName("event") INpcEvent.DialogClosedEvent event) {} + + + // Combat events - damage + @ScriptHook(EnumScriptType.DAMAGED) + default void damaged(@ParamName("event") INpcEvent.DamagedEvent event) {} + + @ScriptHook(EnumScriptType.KILLED) + default void killed(@ParamName("event") INpcEvent.DiedEvent event) {} + + @ScriptHook(EnumScriptType.KILLS) + default void kills(@ParamName("event") INpcEvent.KilledEntityEvent event) {} + + + // Combat events - attacks + @ScriptHook(EnumScriptType.ATTACK_MELEE) + default void meleeAttack(@ParamName("event") INpcEvent.MeleeAttackEvent event) {} + + @ScriptHook(EnumScriptType.ATTACK_SWING) + default void meleeSwing(@ParamName("event") INpcEvent.SwingEvent event) {} + + @ScriptHook(EnumScriptType.RANGED_LAUNCHED) + default void rangedLaunched(@ParamName("event") INpcEvent.RangedLaunchedEvent event) {} + + + // Targeting events + @ScriptHook(EnumScriptType.TARGET) + default void target(@ParamName("event") INpcEvent.TargetEvent event) {} + + @ScriptHook(EnumScriptType.TARGET_LOST) + default void targetLost(@ParamName("event") INpcEvent.TargetLostEvent event) {} + + // Other NPC events + @ScriptHook(EnumScriptType.COLLIDE) + default void collide(@ParamName("event") INpcEvent.CollideEvent event) {} + + @ScriptHook(EnumScriptType.TIMER) + default void timer(@ParamName("event") INpcEvent.TimerEvent event) {} + + + // Projectile events + @ScriptHook(EnumScriptType.PROJECTILE_TICK) + default void projectileTick(@ParamName("event") IProjectileEvent.UpdateEvent event) {} + + @ScriptHook(EnumScriptType.PROJECTILE_IMPACT) + default void projectileImpact(@ParamName("event") IProjectileEvent.ImpactEvent event) {} + + + // Ability events + @ScriptHook(EnumScriptType.ABILITY_START) + default void abilityStart(@ParamName("event") IAbilityEvent.StartEvent event) {} + + @ScriptHook(EnumScriptType.ABILITY_EXECUTE) + default void abilityExecute(@ParamName("event") IAbilityEvent.ExecuteEvent event) {} + + @ScriptHook(EnumScriptType.ABILITY_HIT) + default void abilityHit(@ParamName("event") IAbilityEvent.HitEvent event) {} + + @ScriptHook(EnumScriptType.ABILITY_TICK) + default void abilityTick(@ParamName("event") IAbilityEvent.TickEvent event) {} + + @ScriptHook(EnumScriptType.ABILITY_INTERRUPT) + default void abilityInterrupt(@ParamName("event") IAbilityEvent.InterruptEvent event) {} + + @ScriptHook(EnumScriptType.ABILITY_COMPLETE) + default void abilityComplete(@ParamName("event") IAbilityEvent.CompleteEvent event) {} + } +} diff --git a/src/main/java/noppes/npcs/scripted/item/ScriptCustomItem.java b/src/main/java/noppes/npcs/scripted/item/ScriptCustomItem.java index e03995e16..02f27b71c 100644 --- a/src/main/java/noppes/npcs/scripted/item/ScriptCustomItem.java +++ b/src/main/java/noppes/npcs/scripted/item/ScriptCustomItem.java @@ -8,9 +8,8 @@ import noppes.npcs.NBTTags; import noppes.npcs.api.item.IItemCustom; import noppes.npcs.constants.EnumScriptType; import noppes.npcs.controllers.data.IScriptUnit; -import noppes.npcs.controllers.ScriptContainer; import noppes.npcs.controllers.ScriptController; -import noppes.npcs.controllers.data.INpcScriptHandler; +import noppes.npcs.controllers.data.IScriptHandler; import noppes.npcs.scripted.CustomNPCsException; import java.util.ArrayList; @@ -19,7 +18,7 @@ import java.util.Map; import java.util.Objects; import java.util.TreeMap; -public class ScriptCustomItem extends ScriptCustomizableItem implements IItemCustom, INpcScriptHandler { +public class ScriptCustomItem extends ScriptCustomizableItem implements IItemCustom, IScriptHandler { public List scripts = new ArrayList(); public List errored = new ArrayList(); public String scriptLanguage = "ECMAScript"; @@ -70,7 +69,7 @@ public class ScriptCustomItem extends ScriptCustomizableItem implements IItemCus } @Override - public INpcScriptHandler getScriptHandler() { + public IScriptHandler getScriptHandler() { return this; } @@ -101,9 +100,7 @@ public class ScriptCustomItem extends ScriptCustomizableItem implements IItemCus if (script == null || script.hasErrored() || !script.hasCode()) continue; - if (script instanceof ScriptContainer) { - ((ScriptContainer) script).run(hookName, event); - } + script.run(hookName, event); if (script.hasErrored()) { this.errored.add(i); diff --git a/src/main/java/noppes/npcs/scripted/item/ScriptLinkedItem.java b/src/main/java/noppes/npcs/scripted/item/ScriptLinkedItem.java index 3a777134c..1c4a2ac91 100644 --- a/src/main/java/noppes/npcs/scripted/item/ScriptLinkedItem.java +++ b/src/main/java/noppes/npcs/scripted/item/ScriptLinkedItem.java @@ -4,7 +4,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.api.item.IItemLinked; import noppes.npcs.controllers.LinkedItemController; -import noppes.npcs.controllers.data.INpcScriptHandler; +import noppes.npcs.controllers.data.IScriptHandler; import noppes.npcs.controllers.data.LinkedItem; public class ScriptLinkedItem extends ScriptCustomizableItem implements IItemLinked { @@ -51,7 +51,7 @@ public class ScriptLinkedItem extends ScriptCustomizableItem implements IItemLin } @Override - public INpcScriptHandler getScriptHandler() { + public IScriptHandler getScriptHandler() { if (this.getLinkedItem() == null) return null; return this.getLinkedItem().getScriptHandler();