From f78fc30660cabd588c64a89191ca95b15b8d5798 Mon Sep 17 00:00:00 2001 From: somehussar <148253652+somehussar@users.noreply.github.com> Date: Sat, 3 Jan 2026 02:54:08 +0100 Subject: [PATCH 1/3] Ban java.lang.reflect package --- src/main/java/noppes/npcs/CustomNpcs.java | 3 ++- src/main/java/somehussar/janino/AdvancedClassFilter.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/noppes/npcs/CustomNpcs.java b/src/main/java/noppes/npcs/CustomNpcs.java index ad42bc419..3a6ac92d9 100644 --- a/src/main/java/noppes/npcs/CustomNpcs.java +++ b/src/main/java/noppes/npcs/CustomNpcs.java @@ -173,7 +173,8 @@ public class CustomNpcs { AdvancedClassFilter filter = new AdvancedClassFilter() .addRegexes("noppes\\.npcs\\.api\\..*") .banRegexes(".*ClassLoader.*", - ".*File*."); + ".*File*.", + "java\\.lang\\.reflect\\..*"); for (Consumer consumer : clientClassFilterConsumer) { consumer.accept(filter); diff --git a/src/main/java/somehussar/janino/AdvancedClassFilter.java b/src/main/java/somehussar/janino/AdvancedClassFilter.java index fb1fac6e8..b48de2c30 100644 --- a/src/main/java/somehussar/janino/AdvancedClassFilter.java +++ b/src/main/java/somehussar/janino/AdvancedClassFilter.java @@ -17,7 +17,7 @@ public class AdvancedClassFilter implements LoadClassCondition { public AdvancedClassFilter() { addClasses("java.io.Serializable", "java.util.Iterator"); - addRegexes("java\\.lang\\.."); + addRegexes("java\\.lang\\..*"); } public AdvancedClassFilter addRegexes(String... classRegexes) { From 60af20316583d6692dbf54bc1ebd7b6e95661248 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Mon, 5 Jan 2026 20:32:18 +0200 Subject: [PATCH 2/3] Renamed to moveFromGlobalToLocal --- src/main/java/noppes/npcs/controllers/data/Animation.java | 5 ++++- .../java/noppes/npcs/controllers/data/AnimationData.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/noppes/npcs/controllers/data/Animation.java b/src/main/java/noppes/npcs/controllers/data/Animation.java index fa290975c..c7d006198 100644 --- a/src/main/java/noppes/npcs/controllers/data/Animation.java +++ b/src/main/java/noppes/npcs/controllers/data/Animation.java @@ -360,7 +360,7 @@ public class Animation implements IAnimation { * to the new local instance on entity's AnimationData, * and clear them from the global instance. */ - public void takeTasksFrom(Animation animation) { + public void moveFromGlobalToLocal(Animation animation) { this.onAnimationStart = animation.onAnimationStart; this.onAnimationFrame = animation.onAnimationFrame; this.onAnimationEnd = animation.onAnimationEnd; @@ -368,6 +368,9 @@ public class Animation implements IAnimation { animation.onAnimationEnd = null; animation.onAnimationFrame = null; animation.onAnimationStart = null; + + this.dataStore.putAll(animation.dataStore); + animation.dataStore.clear(); } diff --git a/src/main/java/noppes/npcs/controllers/data/AnimationData.java b/src/main/java/noppes/npcs/controllers/data/AnimationData.java index ea5da6a84..f5e6d80b4 100644 --- a/src/main/java/noppes/npcs/controllers/data/AnimationData.java +++ b/src/main/java/noppes/npcs/controllers/data/AnimationData.java @@ -272,7 +272,7 @@ public class AnimationData implements IAnimationData { newAnim.currentFrame = 0; newAnim.currentFrameTime = 0; newAnim.parent = this; - newAnim.takeTasksFrom((Animation) animation); + newAnim.moveFromGlobalToLocal((Animation) animation); } From b5df6b17094216d838280b64942299587bde256b Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 9 Jan 2026 23:44:07 +0200 Subject: [PATCH 3/3] Moved all janino classes to CNPC+ janino-scripts branch --- src/api | 2 +- .../client/gui/script/GuiJaninoScript.java | 406 ++++++++++++++++++ .../java/noppes/npcs/janino/JaninoScript.java | 276 ++++++++++++ .../noppes/npcs/janino/JaninoScriptable.java | 38 ++ 4 files changed, 721 insertions(+), 1 deletion(-) create mode 100644 src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java create mode 100644 src/main/java/noppes/npcs/janino/JaninoScript.java create mode 100644 src/main/java/noppes/npcs/janino/JaninoScriptable.java diff --git a/src/api b/src/api index 305a3778c..ed5640d23 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit 305a3778c86fed2680b8cad173b7e5fb0f3c98e6 +Subproject commit ed5640d2385d5626a8dff2dd2d0bc59b6c455f4c diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java b/src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java new file mode 100644 index 000000000..874beca4b --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java @@ -0,0 +1,406 @@ +package noppes.npcs.client.gui.script; + +import kamkeel.npcdbc.client.gui.component.SubGuiSelectList; +import noppes.npcs.janino.JaninoScript; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.*; +import net.minecraft.util.StatCollector; +import noppes.npcs.NoppesStringUtils; +import noppes.npcs.client.gui.util.*; +import noppes.npcs.controllers.ScriptController; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.stream.Collectors; + +public class GuiJaninoScript extends GuiNPCInterface implements GuiYesNoCallback, ITextChangeListener, ICustomScrollListener, ISubGuiListener { + + private GuiScriptTextArea textArea; + private int activeTab = 0; + public List allExternalScripts = new ArrayList<>(); + private final int scriptLimit = 1; + public String previousHookClicked = ""; + + // GUI display list + List hooklist = new ArrayList<>(); + + // Map from display name (with parameters if overloaded) to Method + Map hookMap = new HashMap<>(); + + public final GuiScreen parent; + private final JaninoScript container; + + public Runnable saveFunction; + + public GuiJaninoScript(GuiScreen parent, JaninoScript handler) { + this.drawDefaultBackground = true; + this.closeOnEsc = true; + this.xSize = 420; + this.setBackground("menubg.png"); + + this.parent = parent; + this.container = handler; + + createHookList(); + + String lang = handler.getLanguage(); + allExternalScripts.addAll(ScriptController.Instance.getScripts(lang)); + } + + public GuiJaninoScript setSave(Runnable run) { + saveFunction = run; + return this; + } + + public void createHookList() { + // Group all declared methods of the handler's type by their method name + Map> grouped = Arrays.stream(container.type.getDeclaredMethods()) + .collect(Collectors.groupingBy(Method::getName)); + + for (Map.Entry> entry : grouped.entrySet()) { + List methods = entry.getValue(); + + // Sort overloads by number of parameters (ascending) + // This ensures the simplest overload comes first + methods.sort(Comparator.comparingInt(Method::getParameterCount)); + boolean first = true; + + + for (Method m : methods) { + if (Modifier.isFinal(m.getModifiers())) + continue; //skip finals + + 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; + } + } + } + public void initGui() { + this.ySize = (int) ((double) this.xSize * 0.56); + if ((double) this.ySize > (double) this.height * 0.95) { + this.ySize = (int) ((double) this.height * 0.95); + this.xSize = (int) ((double) this.ySize / 0.56); + } + + this.bgScale = (float) this.xSize / 400.0F; + super.initGui(); + this.guiTop += 10; + int yoffset = (int) ((double) this.ySize * 0.02); + GuiMenuTopButton top; + addTopButton(new GuiMenuTopButton(-1, guiLeft + xSize-2 , guiTop - 17, "X")); + this.addTopButton(top = new GuiMenuTopButton(0, this.guiLeft + 4, this.guiTop - 17, "gui.settings")); + int topXoffset = 0; + int topYoffset = 0; + + + if (this.container != null) { + this.addTopButton(top = new GuiMenuTopButton(1, top.xPosition + top.width + topXoffset, top.yPosition + topYoffset, "Script")); + } else { + this.addTopButton(new GuiMenuTopButton(this.scriptLimit, top.xPosition + top.width, top.yPosition, "+")); + } + + top = this.getTopButton(this.activeTab); + if (top == null) { + this.activeTab = 0; + top = this.getTopButton(0); + } + + top.active = true; + if (this.activeTab == 1) { + GuiCustomScroll hooks = new GuiCustomScroll(this, 1); + hooks.allowUserInput = false; + hooks.setSize(108, 198); + hooks.guiLeft = this.guiLeft - 110; + hooks.guiTop = this.guiTop + 14; + + hooks.setUnsortedList(this.hooklist); + this.addScroll(hooks); + GuiNpcLabel hookLabel = new GuiNpcLabel(0, "script.hooks", hooks.guiLeft, this.guiTop + 5); + hookLabel.color = 11184810; + this.addLabel(hookLabel); + JaninoScript container = this.container; + if (textArea == null) + textArea = new GuiScriptTextArea(this, 2, this.guiLeft + 1 + yoffset, this.guiTop + yoffset, this.xSize - 108 - yoffset, (int) ((double) this.ySize * 0.96) - yoffset * 2, container == null ? "" : container.script); + else + textArea.init(this.guiLeft + 1 + yoffset, this.guiTop + yoffset, this.xSize - 108 - yoffset, (int) ((double) this.ySize * 0.96) - yoffset * 2, container == null ? "" : container.script); + textArea.enableCodeHighlighting(); + textArea.setListener(this); + this.closeOnEsc(textArea::closeOnEsc); + this.addTextField(textArea); + + int left1 = this.guiLeft + this.xSize - 104; + this.addButton(new GuiNpcButton(102, left1, this.guiTop + yoffset, 60, 20, "gui.clear")); + this.addButton(new GuiNpcButton(101, left1 + 61, this.guiTop + yoffset, 60, 20, "gui.paste")); + this.addButton(new GuiNpcButton(100, left1, this.guiTop + 21 + yoffset, 60, 20, "gui.copy")); + this.addButton(new GuiNpcButton(105, left1 + 61, this.guiTop + 21 + yoffset, 60, 20, "gui.remove")); + + this.addButton(new GuiNpcButton(107, left1, this.guiTop + 66 + yoffset, 80, 20, "script.loadscript")); + // this.getButton(107).enabled = false; + + GuiCustomScroll scroll = (new GuiCustomScroll(this, 0)).setUnselectable(); + scroll.setSize(100, (int) ((double) this.ySize * 0.54) - yoffset * 2); + scroll.guiLeft = left1; + scroll.guiTop = this.guiTop + 88 + yoffset; + if (container != null) + scroll.setList(container.externalScripts); + + this.addScroll(scroll); + } else { + GuiNpcTextArea var8 = new GuiNpcTextArea(2, this, this.guiLeft + 4 + yoffset, this.guiTop + 6 + yoffset, this.xSize - 160 - yoffset, (int) ((float) this.ySize * 0.92F) - yoffset * 2, this.getConsoleText()); + var8.enabled = false; + this.addTextField(var8); + int var9 = this.guiLeft + this.xSize - 150; + this.addButton(new GuiNpcButton(100, var9, this.guiTop + 125, 60, 20, "gui.copy")); + this.addButton(new GuiNpcButton(102, var9, this.guiTop + 146, 60, 20, "gui.clear")); + this.addLabel(new GuiNpcLabel(1, "script.language", var9, this.guiTop + 15)); + String containerLang = container.getLanguage(); + this.addButton(new GuiNpcButton(103, var9 + 60, this.guiTop + 10, 80, 20, new String[]{containerLang.equals("Java") ? "Janino (JVM 8)" : containerLang}, + this.getScriptIndex())); + // this.getButton(103).enabled = !this.languages.isEmpty(); + this.addLabel(new GuiNpcLabel(2, "gui.enabled", var9, this.guiTop + 36)); + this.addButton(new GuiNpcButton(104, var9 + 60, this.guiTop + 31, 50, 20, new String[]{"gui.no", "gui.yes"}, this.container.getEnabled() ? 1 : 0)); + + this.addButton(new GuiNpcButton(109, var9, this.guiTop + 78, 80, 20, "gui.website")); + this.addButton(new GuiNpcButton(112, var9 + 81, this.guiTop + 78, 80, 20, "gui.forum")); + this.addButton(new GuiNpcButton(110, var9, this.guiTop + 99, 80, 20, "script.apidoc")); + this.addButton(new GuiNpcButton(111, var9 + 81, this.guiTop + 99, 80, 20, "script.apisrc")); + } + + this.xSize = 420; + this.ySize = 256; + } + + public void customScrollClicked(int i, int j, int k, GuiCustomScroll scroll) { + String hook = scroll.getSelected(); + if (this.previousHookClicked.equals(hook)) { + String addString = ""; + if (!this.getTextField(2) + .getText() + .isEmpty()) { + addString = addString + "\n"; + } + + addString = addString + generateMethodStub(hookMap.get(hook)); + this.getTextField(2) + .setText(this.getTextField(2) + .getText() + addString); + this.previousHookClicked = ""; + } else { + this.previousHookClicked = hook; + } + } + + public void confirmClicked(boolean flag, int i) { + if (flag) { + if (i == 0) + this.openLink("https://www.curseforge.com/minecraft/mc-mods/customnpc-plus"); + else if (i == 1) + this.openLink("https://kamkeel.github.io/CustomNPC-Plus/"); + else if (i == 2) + this.openLink("https://kamkeel.github.io/CustomNPC-Plus/"); + else if (i == 3) + this.openLink("http://www.minecraftforge.net/forum/index.php/board,122.0.html"); + + if (i == 10) { //Remove + this.container.setScript(""); + this.activeTab = 0; + } else if (i == 101) { //Paste + this.getTextField(2) + .setText(NoppesStringUtils.getClipboardContents()); + this.setScript(); + } else if (i == 102) { //Clear + if (this.activeTab == 1) + container.script = ""; + else + this.container.clearConsole(); + + this.initGui(); + } + } + + this.displayGuiScreen(this); + } + + protected void actionPerformed(GuiButton guibutton) { + if (guibutton.id == -1) { + close(); + return; + } + + if (guibutton.id == 0) { + this.setScript(); + this.activeTab = 0; + this.initGui(); + container.ensureCompiled(); + } + + if (guibutton.id == this.scriptLimit) { + // if (container.container == null) + //this.container.container = new ScriptContainer(this.container); + // else + // this.setScript(); + this.activeTab = 1; + this.initGui(); + } + + if (guibutton.id == 109) { + this.displayGuiScreen(new GuiConfirmOpenLink(this, "https://kamkeel.github.io/CustomNPC-Plus/", 0, true)); + } else if (guibutton.id == 110) { + this.displayGuiScreen(new GuiConfirmOpenLink(this, "https://github.com/KAMKEEL/CustomNPC-Plus-API", 1, true)); + } else if (guibutton.id == 111) { + this.displayGuiScreen(new GuiConfirmOpenLink(this, "https://github.com/Noppes/CustomNPCsAPI", 2, true)); + } else if (guibutton.id == 112) { + this.displayGuiScreen(new GuiConfirmOpenLink(this, "http://www.minecraftforge.net/forum/index.php/board,122.0.html", 3, true)); + } + + GuiYesNo confirmScreen; + + //Copy + if (guibutton.id == 100) { + NoppesStringUtils.setClipboardContents(this.getTextField(2) + .getText()); + } + //Paste + else if (guibutton.id == 101) { + GuiYesNo guiyesno = new GuiYesNo(this, StatCollector.translateToLocal("gui.paste"), StatCollector.translateToLocal("gui.sure"), 101); + this.displayGuiScreen(guiyesno); + } + //Clear + else if (guibutton.id == 102) { + confirmScreen = new GuiYesNo(this, StatCollector.translateToLocal("gui.clear"), StatCollector.translateToLocal("gui.sure"), 102); + this.displayGuiScreen(confirmScreen); + } + //Enable + else if (guibutton.id == 104) { + this.container.setEnabled(((GuiNpcButton) guibutton).getValue() == 1); + } + //Remove + else if (guibutton.id == 105) { + confirmScreen = new GuiYesNo(this, "", guibutton.displayString, 10); + this.displayGuiScreen(confirmScreen); + } + //Load Script + else if (guibutton.id == 107) { + setSubGui(new SubGuiSelectList(allExternalScripts, container.externalScripts, "All Scripts", "Selected Scripts")); + } + } + + public void subGuiClosed(SubGuiInterface sub) { + if (sub instanceof SubGuiSelectList) + container.setExternalScripts(((SubGuiSelectList) sub).selected); + + } + + /** + * Generates a stub string for a given Method. + */ + public static String generateMethodStub(Method method) { + String mods = java.lang.reflect.Modifier.toString(method.getModifiers()); + if (!mods.isEmpty()) + mods += " "; + + String returnTypeStr = method.getReturnType() + .getSimpleName(); + String name = method.getName(); + + Map typeCount = new HashMap<>(); + 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); + + // append number if same type of arg exists + String paramName = count == 1 ? baseName : baseName + (count - 1); + + return typeName + " " + paramName; + }) + .collect(Collectors.joining(", ")); + + String body; + Class returnType = method.getReturnType(); + if (returnType == void.class) + body = ""; + else if (returnType.isPrimitive()) { + if (returnType == boolean.class) + body = " return false;"; + else if (returnType == char.class) + body = " return '\\0';"; + else + body = " return 0;"; + } else { + body = " return null;"; + } + + return String.format("%s%s %s(%s) {\n%s\n}\n", mods, returnTypeStr, name, params, body); + } + + private String getConsoleText() { + Map map = this.container.getConsoleText(); + StringBuilder builder = new StringBuilder(); + Iterator var3 = map.entrySet() + .iterator(); + + while (var3.hasNext()) { + Map.Entry entry = (Map.Entry) var3.next(); + builder.insert(0, new Date(entry.getKey()) + entry.getValue() + "\n"); + } + + return builder.toString(); + } + + private int getScriptIndex() { + return 0; + } + + private void setScript() { + if (this.activeTab == 1) { + String text = this.getTextField(2) + .getText(); + text = text.replace("\r\n", "\n"); + text = text.replace("\r", "\n"); + container.setScript(text); + } + } + + public void save() { + if (saveFunction != null) + saveFunction.run(); + else if (parent instanceof GuiNPCInterface) + ((GuiNPCInterface) parent).save(); + } + + public void textUpdate(String text) { +// container.setScript(text); + } + + public static GuiJaninoScript create(GuiScreen parent, JaninoScript script, int width, int height) { + GuiJaninoScript gui = new GuiJaninoScript(parent, script); + gui.setWorldAndResolution(Minecraft.getMinecraft(), width, height); + Minecraft.getMinecraft().currentScreen = gui; + gui.initGui(); + return gui; + } + + + @Override + public void close() { + this.save(); + this.setScript(); + container.ensureCompiled(); + parent.setWorldAndResolution(mc, width, height); + parent.initGui(); + mc.currentScreen = parent; + } +} diff --git a/src/main/java/noppes/npcs/janino/JaninoScript.java b/src/main/java/noppes/npcs/janino/JaninoScript.java new file mode 100644 index 000000000..f836e97cf --- /dev/null +++ b/src/main/java/noppes/npcs/janino/JaninoScript.java @@ -0,0 +1,276 @@ +package noppes.npcs.janino; + +import cpw.mods.fml.common.FMLCommonHandler; +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.controllers.ScriptController; +import org.codehaus.commons.compiler.InternalCompilerException; +import org.codehaus.commons.compiler.Sandbox; + +import java.security.*; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; + +public abstract class JaninoScript { + public boolean enabled; + private String language = "Java"; + public TreeMap console = new TreeMap(); + + /** + * Text written in the script GUI + */ + public String script = ""; + /** + * This script's selected external files + * stored in "world/customnpcs/scripts/java" + */ + public List externalScripts = new ArrayList<>(); + /** + * To evaluate if script/externalScripts were changed or not, + * and compile the fullScript freshly if so. + */ + public boolean evaluated; + + public final Class type; + protected final Sandbox sandbox; + public final IScriptBodyBuilder builder; + protected IScriptClassBody scriptBody; + + protected JaninoScript(Class type, Consumer> buildSettings) { + this.type = type; + this.builder = IScriptBodyBuilder + .getBuilder(type, CustomNpcs.getClientCompiler()); + buildSettings.accept(builder); + + Permissions permissions = new Permissions(); + permissions.setReadOnly(); + sandbox = new Sandbox(permissions); + + this.scriptBody = builder.build(); + } + + protected T getUnsafe() { + return scriptBody.get(); + } + + public R call(Function fn) { + ensureCompiled(); + + T t = getUnsafe(); + if (t == null) + return null; + +// CodeSource cs = t.getClass().getProtectionDomain().getCodeSource(); +// ProtectionDomain pd = new ProtectionDomain(cs, new Permissions()); + + try { + return sandbox.confine((PrivilegedAction) () -> fn.apply(t)); +// return AccessController.doPrivileged((PrivilegedAction) () -> fn.apply(t), new AccessControlContext( +// new ProtectionDomain[] { +// pd +// } +// )); + } catch (Exception e) { + appendConsole("Runtime Error: " + e.getMessage()); + return null; + } + } + + public void run(Consumer fn) { + ensureCompiled(); + + T t = getUnsafe(); + if (t == null) + return; + + try { + sandbox.confine((PrivilegedAction) () -> { + fn.accept(t); + return null; + }); + } catch (Exception e) { + appendConsole("Runtime Error: " + e.getMessage()); + } + } + + public void unload() { + } + + /** + * Feed the code into the engine and compile it + */ + public void compileScript(String code) { + + try { + scriptBody.setScript(code); + } catch (InternalCompilerException e ) { + Throwable parentCause = null; + Throwable cause = e; + + appendConsole("Compilation error: " + e.getMessage()); + + while (cause.getCause() != null) { parentCause = cause; cause = cause.getCause(); } + Throwable rootCause = cause; + + if (e != cause) { + appendConsole("\n"); + + if (parentCause != null) + appendConsole(parentCause.getMessage()); + appendConsole(rootCause.getMessage()); + } + } catch (Exception e) { + appendConsole("Unknown error: " + e.getMessage()); + } + } + + public void compileScript() { + compileScript(getFullCode()); + } + + public void ensureCompiled() { + if (!isEnabled()) { + if (!evaluated) { + compileScript(""); + evaluated = true; + } + return; + } + + int global = ScriptController.Instance.globalRevision; + + if (!evaluated || global != lastSeenGlobalRevision) { + compileScript(); + lastSeenGlobalRevision = global; + evaluated = true; + } + } + + /** + * globalRevision is incremented on server + * each time externalScripts are updated + * then sent to client. + */ + private int lastSeenGlobalRevision; + + private String getFullCode() { + if (!isEnabled()) + return ""; + + StringBuilder sb = new StringBuilder(); + + if (ConfigScript.RunLoadedScriptsFirst) + this.appendExternalScripts(sb); + + // Main script + if (this.script != null && !this.script.isEmpty()) + sb.append(this.script).append("\n"); + + if (!ConfigScript.RunLoadedScriptsFirst) + this.appendExternalScripts(sb); + + return sb.toString(); + } + + private void appendExternalScripts(StringBuilder sb) { + for (String scriptName : externalScripts) { + String code = ScriptController.Instance.scripts.get(scriptName); + if (code != null && !code.isEmpty()) + sb.append(code).append("\n"); + } + } + + public void setScript(String script) { + this.script = script; + this.evaluated = false; + } + + public void setExternalScripts(List externalScripts) { + this.externalScripts = externalScripts; + this.evaluated = false; + } + + + public NBTTagCompound writeToNBT(NBTTagCompound compound) { + compound.setBoolean("enabled", enabled); + compound.setTag("console", NBTTags.NBTLongStringMap(this.console)); + compound.setTag("externalScripts", NBTTags.nbtStringList(this.externalScripts)); + compound.setString("script", script); + return compound; + } + + public JaninoScript readFromNBT(NBTTagCompound compound) { + this.enabled = compound.getBoolean("enabled"); + this.console = NBTTags.GetLongStringMap(compound.getTagList("console", 10)); + setExternalScripts(NBTTags.getStringList(compound.getTagList("externalScripts", 10))); + setScript(compound.getString("script")); //after everything else is read + return this; + } + + public boolean isEnabled() { + return this.enabled && ScriptController.HasStart && ConfigScript.ScriptingEnabled; + } + + public boolean isClient() { + return FMLCommonHandler.instance() + .getEffectiveSide() + .isClient(); + } + + public boolean getEnabled() { + return this.enabled; + } + + public void setEnabled(boolean b) { + if (this.enabled != b) { + this.enabled = b; + this.evaluated = false; + } + } + + public String getLanguage() { + return this.language; + } + + public void appendConsole(String message) { + if (message != null && !message.isEmpty()) { + long time = System.currentTimeMillis(); + if (this.console.containsKey(time)) { + message = (String) this.console.get(time) + "\n" + message; + } + + this.console.put(time, message); + + while (this.console.size() > 40) { + this.console.remove(this.console.firstKey()); + } + } + } + + public Map getConsoleText() { + TreeMap map = new TreeMap(); + int tab = 0; + + Iterator var5 = console.entrySet() + .iterator(); + + while (var5.hasNext()) { + Map.Entry longStringEntry = (Map.Entry) var5.next(); + map.put(longStringEntry.getKey(), " tab " + tab + ":\n" + (String) longStringEntry.getValue()); + } + + + return map; + } + + public void clearConsole() { + console.clear(); + } +} + + diff --git a/src/main/java/noppes/npcs/janino/JaninoScriptable.java b/src/main/java/noppes/npcs/janino/JaninoScriptable.java new file mode 100644 index 000000000..9700bf893 --- /dev/null +++ b/src/main/java/noppes/npcs/janino/JaninoScriptable.java @@ -0,0 +1,38 @@ +package noppes.npcs.janino; + +import net.minecraft.nbt.NBTTagCompound; + +import java.util.function.Supplier; + +/** + + */ +public interface JaninoScriptable> { + + boolean hasScript(); + + JaninoScript getScript(); + + JaninoScript createScript(); + + void deleteScript(); + + void unloadScript(); + + static > S readFromNBT(NBTTagCompound compound, S script, Supplier factory) { + if (compound.hasKey("Script")) { + if (script == null) + script = factory.get(); + + script.readFromNBT(compound.getCompoundTag("Script")); + } + return script; + } + + static NBTTagCompound writeToNBT(NBTTagCompound compound, JaninoScript script) { + if (script != null) + compound.setTag("Script", script.writeToNBT(new NBTTagCompound())); + + return compound; + } +}