diff --git a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/ScriptPIDSPreset.java b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/ScriptPIDSPreset.java index 9db4bb49..b801aacb 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/ScriptPIDSPreset.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/ScriptPIDSPreset.java @@ -5,6 +5,9 @@ import com.lx862.jcm.mod.block.entity.PIDSBlockEntity; import com.lx862.jcm.mod.data.pids.preset.components.base.PIDSComponent; import com.lx862.jcm.mod.data.scripting.PIDSScriptInstance; +import com.lx862.jcm.mod.data.scripting.PIDSScriptObject; +import com.lx862.jcm.mod.data.scripting.ScriptInstanceManager; +import com.lx862.jcm.mod.data.scripting.base.ScriptInstance; import com.lx862.jcm.mod.data.scripting.util.*; import com.lx862.jcm.mod.util.JCMLogger; import org.mozilla.javascript.Context; @@ -26,12 +29,12 @@ import java.util.List; public class ScriptPIDSPreset extends PIDSPresetBase { - private final PIDSScriptInstance scriptInstance; + public final Scriptable scope; private static final Identifier PLACEHOLDER_BACKGROUND = Constants.id("textures/block/pids/rv_default.png"); - public ScriptPIDSPreset(String id, @Nullable String name, PIDSScriptInstance scriptInstance) { + public ScriptPIDSPreset(String id, @Nullable String name, Scriptable scope) { super(id, name, false); - this.scriptInstance = scriptInstance; + this.scope = scope; } public static ScriptPIDSPreset parse(JsonObject rootJsonObject) { @@ -62,7 +65,7 @@ public static ScriptPIDSPreset parse(JsonObject rootJsonObject) { cx.evaluateString(scope, "\"use strict\"", "", 1, null); cx.evaluateString(scope, scriptText, scriptLocation.getNamespace() + ":" + scriptLocation.getPath(), 1, null); - ScriptPIDSPreset preset = new ScriptPIDSPreset(id, name, new PIDSScriptInstance(scope)); + ScriptPIDSPreset preset = new ScriptPIDSPreset(id, name, scope); JCMLogger.info("Script for " + scriptLocation.getNamespace() + ":" + scriptLocation.getPath() + " has been parsed!"); return preset; } catch (Exception e) { @@ -74,21 +77,30 @@ public static ScriptPIDSPreset parse(JsonObject rootJsonObject) { @Override public void render(PIDSBlockEntity be, GraphicsHolder graphicsHolder, World world, BlockPos pos, Direction facing, ObjectArrayList arrivals, boolean[] rowHidden, float tickDelta, int x, int y, int width, int height) { - this.scriptInstance.execute(graphicsHolder, be); - - graphicsHolder.translate(0, 0, -0.5); - PIDSContext pidsContext = new PIDSContext(world, pos, be.getCustomMessages(), arrivals, tickDelta); - for(PIDSComponent component : new ArrayList<>(this.scriptInstance.components)) { - graphicsHolder.translate(0, 0, -0.02); - graphicsHolder.push(); - component.render(graphicsHolder, null, facing, pidsContext); - graphicsHolder.pop(); + ScriptInstance scriptInstance = ScriptInstanceManager.getInstance(pos.asLong(), () -> new PIDSScriptInstance(pos, scope)); + PIDSScriptObject obj = new PIDSScriptObject(graphicsHolder, be.getCustomMessages(), be.getRowHidden(), be.platformNumberHidden()); + + if(scriptInstance instanceof PIDSScriptInstance) { + PIDSScriptInstance pidsScriptInstance = (PIDSScriptInstance)scriptInstance; + scriptInstance.execute(obj, () -> { + pidsScriptInstance.components.clear(); + pidsScriptInstance.components.addAll(obj.getDrawCalls()); + }); + + graphicsHolder.translate(0, 0, -0.5); + PIDSContext pidsContext = new PIDSContext(world, pos, be.getCustomMessages(), arrivals, tickDelta); + for(PIDSComponent component : new ArrayList<>(pidsScriptInstance.components)) { + graphicsHolder.translate(0, 0, -0.02); + graphicsHolder.push(); + component.render(graphicsHolder, null, facing, pidsContext); + graphicsHolder.pop(); + } } } @Override public List getComponents(ObjectArrayList arrivals, String[] customMessages, boolean[] rowHidden, int x, int y, int screenWidth, int screenHeight, int rows, boolean hidePlatform) { - return this.scriptInstance.components; + return new ArrayList<>(); } @Override diff --git a/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/PIDSScriptInstance.java b/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/PIDSScriptInstance.java index 03ae82d1..ec6d8de8 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/PIDSScriptInstance.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/PIDSScriptInstance.java @@ -1,42 +1,26 @@ package com.lx862.jcm.mod.data.scripting; -import com.lx862.jcm.mod.block.entity.PIDSBlockEntity; import com.lx862.jcm.mod.data.pids.preset.components.base.PIDSComponent; import com.lx862.jcm.mod.data.scripting.base.ScriptInstance; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.Function; import org.mozilla.javascript.Scriptable; -import org.mtr.mapping.mapper.GraphicsHolder; +import org.mtr.mapping.holder.BlockEntity; +import org.mtr.mapping.holder.BlockPos; +import org.mtr.mapping.holder.MinecraftClient; import java.util.ArrayList; import java.util.List; public class PIDSScriptInstance extends ScriptInstance { public List components; + private final BlockEntity be; - public PIDSScriptInstance(Scriptable scope) { + public PIDSScriptInstance(BlockPos pos, Scriptable scope) { super(scope); + this.be = MinecraftClient.getInstance().getWorldMapped().getBlockEntity(pos); this.components = new ArrayList<>(); } - public void execute(GraphicsHolder graphicsHolder, PIDSBlockEntity be) { - execute(() -> { - try { - Context cx = Context.enter(); - cx.setLanguageVersion(Context.VERSION_ES6); - ScriptContext ctx = new ScriptContext(); - PIDSScriptObject pidsContext = new PIDSScriptObject(graphicsHolder, be.getCustomMessages(), be.getRowHidden(), be.platformNumberHidden()); - Object renderFunction = scope.get("render", scope); - Object[] renderParams = new Object[]{ctx, null, pidsContext}; - - if(renderFunction instanceof Scriptable && renderFunction != Scriptable.NOT_FOUND) { - ((Function)renderFunction).call(cx, scope, scope, renderParams); - } - components.clear(); - components.addAll(pidsContext.getDrawCalls()); - } finally { - Context.exit(); - } - }); + public boolean isDead() { + return be.isRemoved(); } } diff --git a/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/ScriptInstanceManager.java b/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/ScriptInstanceManager.java new file mode 100644 index 00000000..bb167818 --- /dev/null +++ b/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/ScriptInstanceManager.java @@ -0,0 +1,39 @@ +package com.lx862.jcm.mod.data.scripting; + +import com.lx862.jcm.mod.data.scripting.base.ScriptInstance; +import com.lx862.jcm.mod.util.JCMLogger; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +public class ScriptInstanceManager { + private final static Map instances = new HashMap<>(); + + public static ScriptInstance getInstance(long uuid, Supplier getInstance) { + if(instances.containsKey(uuid)) { + return instances.get(uuid); + } else { + ScriptInstance instance = getInstance.get(); + instances.put(uuid, instance); + return instance; + } + } + + public static void clearDeadInstance() { + int count = 0; + for(Map.Entry entry : new HashMap<>(instances).entrySet()) { + if(entry.getValue().isDead()) { + count++; + instances.remove(entry.getKey()); + } + } + if(count > 0) { + JCMLogger.info("[Scripting] Removed {} dead instance", count); + } + } + + public static void reset() { + instances.clear(); + } +} diff --git a/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/base/ScriptInstance.java b/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/base/ScriptInstance.java index f2041d00..c67a9d0b 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/base/ScriptInstance.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/base/ScriptInstance.java @@ -1,8 +1,12 @@ package com.lx862.jcm.mod.data.scripting.base; +import com.lx862.jcm.mod.data.scripting.PIDSScriptObject; +import com.lx862.jcm.mod.data.scripting.ScriptContext; import com.lx862.jcm.mod.data.scripting.ScriptManager; import com.lx862.jcm.mod.data.scripting.util.TimingUtil; import com.lx862.jcm.mod.util.JCMLogger; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Function; import org.mozilla.javascript.Scriptable; import java.util.concurrent.Future; @@ -10,6 +14,7 @@ public abstract class ScriptInstance { private static final int SCRIPT_RESET_TIME = 4000; private long lastFailedTime = -1; + protected Scriptable state; protected Future scriptTask; protected final Scriptable scope; public double lastExecuteTime = 0; @@ -18,20 +23,36 @@ public ScriptInstance(Scriptable scope) { this.scope = scope; } - public void execute(Runnable runScript) { + public void execute(Object targetObject, Runnable callback) { if(scriptTask == null || scriptTask.isDone()) { if(lastFailedTime == -1 || System.currentTimeMillis() - lastFailedTime > SCRIPT_RESET_TIME) { scriptTask = ScriptManager.submitScript(() -> { TimingUtil.prepareForScript(this); try { - runScript.run(); + try { + Context cx = Context.enter(); + cx.setLanguageVersion(Context.VERSION_ES6); + if(state == null) state = cx.newObject(scope); + ScriptContext ctx = new ScriptContext(); + Object renderFunction = scope.get("render", scope); + Object[] renderParams = new Object[]{ctx, state, targetObject}; + + if(renderFunction instanceof Scriptable && renderFunction != Scriptable.NOT_FOUND) { + ((Function)renderFunction).call(cx, scope, scope, renderParams); + } + } finally { + Context.exit(); + } } catch (Exception e) { - e.printStackTrace(); JCMLogger.error("[PIDS] Error executing script!"); + e.printStackTrace(); lastFailedTime = System.currentTimeMillis(); } + callback.run(); }); } } } + + public abstract boolean isDead(); } diff --git a/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/util/ScriptResourceUtil.java b/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/util/ScriptResourceUtil.java index bbc928bb..9f5c2fbd 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/util/ScriptResourceUtil.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/data/scripting/util/ScriptResourceUtil.java @@ -15,7 +15,7 @@ public static void print(Object... objs) { for(Object obj : objs) { sb.append(obj.toString()); } - JCMLogger.info("[PIDS] {}", sb.toString().trim()); + JCMLogger.info("[Scripting] {}", sb.toString().trim()); } public static Identifier identifier(String textForm) { diff --git a/fabric/src/main/java/com/lx862/jcm/mod/registry/Events.java b/fabric/src/main/java/com/lx862/jcm/mod/registry/Events.java index 502340b9..3f890c9a 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/registry/Events.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/registry/Events.java @@ -2,6 +2,7 @@ import com.lx862.jcm.mod.data.JCMClientStats; import com.lx862.jcm.mod.data.JCMServerStats; +import com.lx862.jcm.mod.data.scripting.ScriptInstanceManager; import com.lx862.jcm.mod.resources.JCMResourceManager; import com.lx862.jcm.mod.resources.mcmeta.McMetaManager; @@ -19,6 +20,7 @@ public static void registerClient() { JCMRegistryClient.REGISTRY_CLIENT.eventRegistryClient.registerStartClientTick(() -> { JCMClientStats.incrementGameTick(); McMetaManager.tick(); + ScriptInstanceManager.clearDeadInstance(); }); } } diff --git a/fabric/src/main/java/com/lx862/jcm/mod/resources/JCMResourceManager.java b/fabric/src/main/java/com/lx862/jcm/mod/resources/JCMResourceManager.java index 7ff75105..45b9cfa6 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/resources/JCMResourceManager.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/resources/JCMResourceManager.java @@ -5,6 +5,8 @@ import com.google.gson.JsonParser; import com.lx862.jcm.mod.Constants; import com.lx862.jcm.mod.data.pids.PIDSManager; +import com.lx862.jcm.mod.data.scripting.ScriptInstanceManager; +import com.lx862.jcm.mod.data.scripting.ScriptManager; import com.lx862.jcm.mod.render.text.TextRenderingManager; import com.lx862.jcm.mod.resources.mcmeta.McMetaManager; import com.lx862.jcm.mod.util.JCMLogger; @@ -19,6 +21,8 @@ public static void reload() { TextRenderingManager.initialize(); McMetaManager.reset(); PIDSManager.reset(); + ScriptManager.reset(); + ScriptInstanceManager.reset(); parseCustomResources(); }