events handling is disabled now when potentially triggered from the scarpet script preventing from recursive callbacks.

This commit is contained in:
gnembon committed 2021-09-06 02:37:08 -03:00
1 parent 8325783bf4
commit 229d0b037b
5 files changed
+104 -32

No files matched your search

@@ -6,6 +6,7 @@ import carpet.helpers.TickSpeed;
import carpet.script.exception.IntegrityException; import carpet.script.exception.IntegrityException;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.InvalidCallbackException; import carpet.script.exception.InvalidCallbackException;
import carpet.script.utils.GlocalFlag;
import carpet.script.value.BlockValue; import carpet.script.value.BlockValue;
import carpet.script.value.BooleanValue; import carpet.script.value.BooleanValue;
import carpet.script.value.EntityValue; import carpet.script.value.EntityValue;
@@ -73,8 +74,7 @@ public class CarpetEventServer
public final CarpetScriptServer scriptServer; public final CarpetScriptServer scriptServer;
private static final List<Value> NOARGS = Collections.emptyList(); private static final List<Value> NOARGS = Collections.emptyList();
public final Map<String, Event> customEvents = new HashMap<>(); public final Map<String, Event> customEvents = new HashMap<>();
public GlocalFlag handleEvents = new GlocalFlag(true);
public enum CallbackResult public enum CallbackResult
{ {
@@ -194,31 +194,33 @@ public class CarpetEventServer
*/ */
public void call(Supplier<List<Value>> argumentSupplier, Supplier<ServerCommandSource> cmdSourceSupplier) public void call(Supplier<List<Value>> argumentSupplier, Supplier<ServerCommandSource> cmdSourceSupplier)
{ {
if (callList.size() > 0) if (callList.size() > 0 && CarpetServer.scriptServer != null)
{ {
CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet events", CarpetProfiler.TYPE.GENERAL); CarpetServer.scriptServer.events.handleEvents.runIfEnabled( () -> {
List<Value> argv = argumentSupplier.get(); // empty for onTickDone CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet events", CarpetProfiler.TYPE.GENERAL);
ServerCommandSource source; List<Value> argv = argumentSupplier.get(); // empty for onTickDone
try ServerCommandSource source;
{ try
source = cmdSourceSupplier.get(); {
} source = cmdSourceSupplier.get();
catch (NullPointerException noReference) // todo figure out what happens when closing. }
{ catch (NullPointerException noReference) // todo figure out what happens when closing.
return; {
} return;
String nameCheck = perPlayerDistribution?source.getName():null; }
assert argv.size() == reqArgs; String nameCheck = perPlayerDistribution ? source.getName() : null;
List<Callback> fails = new ArrayList<>(); assert argv.size() == reqArgs;
for (Callback call: callList) List<Callback> 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). // supressing calls where target player hosts simply don't match
if (nameCheck != null && call.optionalTarget != null && !nameCheck.equals(call.optionalTarget)) continue; // handling global hosts with player targets is left to when the host is resolved (few calls deeper).
if (call.execute(source, argv) == CallbackResult.FAIL) fails.add(call); 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); for (Callback call : fails) callList.remove(call);
CarpetProfiler.end_current_section(currentSection);
});
} }
} }
@@ -72,7 +72,7 @@ public class CarpetExpression
Value playerValue = new EntityValue(e).bindTo("p"); Value playerValue = new EntityValue(e).bindTo("p");
context.with("p", (cc, tt) -> playerValue); 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) catch (ExpressionException e)
{ {
@@ -109,7 +109,7 @@ public class CarpetExpression
Value playerValue = new EntityValue(e).bindTo("p"); Value playerValue = new EntityValue(e).bindTo("p");
context.with("p", (cc, tt) -> playerValue); context.with("p", (cc, tt) -> playerValue);
} }
return this.expr.eval(context); return CarpetServer.scriptServer.events.handleEvents.getWhileDisabled(()-> this.expr.eval(context));
} }
catch (ExpressionException e) catch (ExpressionException e)
{ {
@@ -710,7 +710,7 @@ public class CarpetScriptHost extends ScriptHost
{ {
try try
{ {
return call(source, function, args); return scriptServer.events.handleEvents.getWhileDisabled(() -> call(source, function, args));
} }
catch (CarpetExpressionException exc) 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 // TODO: this is just for now - invoke would be able to invoke other hosts scripts
assertAppIntegrity(function.getModule()); assertAppIntegrity(function.getModule());
Context context = new CarpetContext(this, source, BlockPos.ORIGIN); 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), () -> function.lazyEval(context, Context.VOID, function.getExpression(), function.getToken(), argv),
context, context,
Context.VOID Context.VOID
); ));
} }
catch (ExpressionException e) catch (ExpressionException e)
{ {
@@ -891,6 +891,7 @@ public class CarpetScriptHost extends ScriptHost
{ {
ServerPlayerEntity player = (user==null)?null:scriptServer.server.getPlayerManager().getPlayer(user); ServerPlayerEntity player = (user==null)?null:scriptServer.server.getPlayerManager().getPlayer(user);
ServerCommandSource source = (player != null)?player.getCommandSource():scriptServer.server.getCommandSource(); ServerCommandSource source = (player != null)?player.getCommandSource():scriptServer.server.getCommandSource();
return scriptServer.events.handleEvents.getWhileDisabled(()->{
try try
{ {
return callUDF(BlockPos.ORIGIN, source, fun, arguments); return callUDF(BlockPos.ORIGIN, source, fun, arguments);
@@ -899,6 +900,7 @@ public class CarpetScriptHost extends ScriptHost
{ {
return Value.NULL; return Value.NULL;
} }
});
} }
@@ -375,7 +375,7 @@ public class CarpetScriptServer
{ {
CarpetProfiler.ProfilerToken token; CarpetProfiler.ProfilerToken token;
token = CarpetProfiler.start_section(null, "Scarpet schedule", CarpetProfiler.TYPE.GENERAL); token = CarpetProfiler.start_section(null, "Scarpet schedule", CarpetProfiler.TYPE.GENERAL);
events.tick(); events.handleEvents.getWhileDisabled( () -> {events.tick(); return null;});
CarpetProfiler.end_current_section(token); CarpetProfiler.end_current_section(token);
token = CarpetProfiler.start_section(null, "Scarpet app data", CarpetProfiler.TYPE.GENERAL); token = CarpetProfiler.start_section(null, "Scarpet app data", CarpetProfiler.TYPE.GENERAL);
for (CarpetScriptHost host : modules.values()) for (CarpetScriptHost host : modules.values())
@@ -0,0 +1,68 @@
package carpet.script.utils;
import java.util.function.Supplier;
public class GlocalFlag extends ThreadLocal<Boolean>
{
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 <T> - returned value of that action, whatever that might be
* @return result of the action
*/
public <T> T getWhileDisabled(Supplier<T> action)
{
return whileValueReturn(!initial, action);
}
private <T> T whileValueReturn(boolean what, Supplier<T> 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;
}
}