diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java index a0d2e6ab..890b8584 100644 --- a/src/main/java/carpet/script/CarpetEventServer.java +++ b/src/main/java/carpet/script/CarpetEventServer.java @@ -6,6 +6,7 @@ import carpet.helpers.TickSpeed; import carpet.script.exception.IntegrityException; import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InvalidCallbackException; +import carpet.script.utils.GlocalFlag; import carpet.script.value.BlockValue; import carpet.script.value.BooleanValue; import carpet.script.value.EntityValue; @@ -73,8 +74,7 @@ public class CarpetEventServer public final CarpetScriptServer scriptServer; private static final List NOARGS = Collections.emptyList(); public final Map customEvents = new HashMap<>(); - - + public GlocalFlag handleEvents = new GlocalFlag(true); public enum CallbackResult { @@ -194,31 +194,33 @@ public class CarpetEventServer */ public void call(Supplier> argumentSupplier, Supplier cmdSourceSupplier) { - if (callList.size() > 0) + if (callList.size() > 0 && CarpetServer.scriptServer != null) { - CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet events", CarpetProfiler.TYPE.GENERAL); - List argv = argumentSupplier.get(); // empty for onTickDone - ServerCommandSource source; - try - { - source = cmdSourceSupplier.get(); - } - catch (NullPointerException noReference) // todo figure out what happens when closing. - { - return; - } - String nameCheck = perPlayerDistribution?source.getName():null; - assert argv.size() == reqArgs; - List fails = new ArrayList<>(); - for (Callback call: callList) - { - // supressing calls where target player hosts simply don't match - // handling global hosts with player targets is left to when the host is resolved (few calls deeper). - if (nameCheck != null && call.optionalTarget != null && !nameCheck.equals(call.optionalTarget)) continue; - if (call.execute(source, argv) == CallbackResult.FAIL) fails.add(call); - } - for (Callback call : fails) callList.remove(call); - CarpetProfiler.end_current_section(currentSection); + CarpetServer.scriptServer.events.handleEvents.runIfEnabled( () -> { + CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet events", CarpetProfiler.TYPE.GENERAL); + List argv = argumentSupplier.get(); // empty for onTickDone + ServerCommandSource source; + try + { + source = cmdSourceSupplier.get(); + } + catch (NullPointerException noReference) // todo figure out what happens when closing. + { + return; + } + String nameCheck = perPlayerDistribution ? source.getName() : null; + assert argv.size() == reqArgs; + List fails = new ArrayList<>(); + for (Callback call : callList) + { + // supressing calls where target player hosts simply don't match + // handling global hosts with player targets is left to when the host is resolved (few calls deeper). + if (nameCheck != null && call.optionalTarget != null && !nameCheck.equals(call.optionalTarget)) continue; + if (call.execute(source, argv) == CallbackResult.FAIL) fails.add(call); + } + for (Callback call : fails) callList.remove(call); + CarpetProfiler.end_current_section(currentSection); + }); } } diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index e23e2971..d8b9c5f9 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -72,7 +72,7 @@ public class CarpetExpression Value playerValue = new EntityValue(e).bindTo("p"); context.with("p", (cc, tt) -> playerValue); } - return this.expr.eval(context).getBoolean(); + return CarpetServer.scriptServer.events.handleEvents.getWhileDisabled(()-> this.expr.eval(context).getBoolean()); } catch (ExpressionException e) { @@ -109,7 +109,7 @@ public class CarpetExpression Value playerValue = new EntityValue(e).bindTo("p"); context.with("p", (cc, tt) -> playerValue); } - return this.expr.eval(context); + return CarpetServer.scriptServer.events.handleEvents.getWhileDisabled(()-> this.expr.eval(context)); } catch (ExpressionException e) { diff --git a/src/main/java/carpet/script/CarpetScriptHost.java b/src/main/java/carpet/script/CarpetScriptHost.java index 5895a805..a25c3c20 100644 --- a/src/main/java/carpet/script/CarpetScriptHost.java +++ b/src/main/java/carpet/script/CarpetScriptHost.java @@ -710,7 +710,7 @@ public class CarpetScriptHost extends ScriptHost { try { - return call(source, function, args); + return scriptServer.events.handleEvents.getWhileDisabled(() -> call(source, function, args)); } catch (CarpetExpressionException exc) { @@ -815,11 +815,11 @@ public class CarpetScriptHost extends ScriptHost // TODO: this is just for now - invoke would be able to invoke other hosts scripts assertAppIntegrity(function.getModule()); Context context = new CarpetContext(this, source, BlockPos.ORIGIN); - return function.getExpression().evalValue( + return scriptServer.events.handleEvents.getWhileDisabled(() -> function.getExpression().evalValue( () -> function.lazyEval(context, Context.VOID, function.getExpression(), function.getToken(), argv), context, Context.VOID - ); + )); } catch (ExpressionException e) { @@ -891,6 +891,7 @@ public class CarpetScriptHost extends ScriptHost { ServerPlayerEntity player = (user==null)?null:scriptServer.server.getPlayerManager().getPlayer(user); ServerCommandSource source = (player != null)?player.getCommandSource():scriptServer.server.getCommandSource(); + return scriptServer.events.handleEvents.getWhileDisabled(()->{ try { return callUDF(BlockPos.ORIGIN, source, fun, arguments); @@ -899,6 +900,7 @@ public class CarpetScriptHost extends ScriptHost { return Value.NULL; } + }); } diff --git a/src/main/java/carpet/script/CarpetScriptServer.java b/src/main/java/carpet/script/CarpetScriptServer.java index 2c5935c6..4624cc52 100644 --- a/src/main/java/carpet/script/CarpetScriptServer.java +++ b/src/main/java/carpet/script/CarpetScriptServer.java @@ -375,7 +375,7 @@ public class CarpetScriptServer { CarpetProfiler.ProfilerToken token; token = CarpetProfiler.start_section(null, "Scarpet schedule", CarpetProfiler.TYPE.GENERAL); - events.tick(); + events.handleEvents.getWhileDisabled( () -> {events.tick(); return null;}); CarpetProfiler.end_current_section(token); token = CarpetProfiler.start_section(null, "Scarpet app data", CarpetProfiler.TYPE.GENERAL); for (CarpetScriptHost host : modules.values()) diff --git a/src/main/java/carpet/script/utils/GlocalFlag.java b/src/main/java/carpet/script/utils/GlocalFlag.java new file mode 100644 index 00000000..af9ae8f4 --- /dev/null +++ b/src/main/java/carpet/script/utils/GlocalFlag.java @@ -0,0 +1,68 @@ +package carpet.script.utils; + +import java.util.function.Supplier; + +public class GlocalFlag extends ThreadLocal +{ + private final boolean initial; + + public GlocalFlag(boolean initial) + { + this.initial = initial; + } + + @Override + public Boolean initialValue() + { + return initial; + } + + /** + * Allows to thread-safely wrap a call while disabling a global flag and setting it back up right after. + * @param action - callback to invoke when the wrapping is all setup + * @param - returned value of that action, whatever that might be + * @return result of the action + */ + public T getWhileDisabled(Supplier action) + { + return whileValueReturn(!initial, action); + } + + private T whileValueReturn(boolean what, Supplier action) + { + T result; + boolean previous; + synchronized (this) + { + previous = get(); + set(what); + } + try + { + result = action.get(); + } + finally + { + set(previous); + } + return result; + } + + public boolean runIfEnabled(Runnable action) + { + synchronized (this) + { + if (get() != initial) return false; + set(!initial); + } + try + { + action.run(); + } + finally + { + set(initial); + } + return true; + } +}