rework of the event system, allowing apps to function more independently and allowing for player scoped apps to handle global events. fixes #596
This commit is contained in:
1 parent
926c1a8e63
commit
d29f49967f
13 files changed
+367
-246
No files matched your search
@@ -5,7 +5,19 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import carpet.commands.*;
|
||||
import carpet.commands.CounterCommand;
|
||||
import carpet.commands.DistanceCommand;
|
||||
import carpet.commands.DrawCommand;
|
||||
import carpet.commands.InfoCommand;
|
||||
import carpet.commands.LogCommand;
|
||||
import carpet.commands.MobAICommand;
|
||||
import carpet.commands.PerimeterInfoCommand;
|
||||
import carpet.commands.PlayerCommand;
|
||||
import carpet.commands.ProfileCommand;
|
||||
import carpet.commands.ScriptCommand;
|
||||
import carpet.commands.SpawnCommand;
|
||||
import carpet.commands.TestCommand;
|
||||
import carpet.commands.TickCommand;
|
||||
import carpet.network.ServerNetworkHandler;
|
||||
import carpet.helpers.HopperCounter;
|
||||
import carpet.helpers.TickSpeed;
|
||||
@@ -143,6 +155,7 @@ public class CarpetServer implements ClientModInitializer,DedicatedServerModInit
|
||||
{
|
||||
ServerNetworkHandler.onPlayerJoin(player);
|
||||
LoggerRegistry.playerConnected(player);
|
||||
scriptServer.onPlayerJoin(player);
|
||||
extensions.forEach(e -> e.onPlayerLoggedIn(player));
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import net.minecraft.block.Block;
|
||||
@@ -84,7 +85,7 @@ public class ScriptCommand
|
||||
private static CompletableFuture<Suggestions> suggestCode(
|
||||
CommandContext<ServerCommandSource> context,
|
||||
SuggestionsBuilder suggestionsBuilder
|
||||
)
|
||||
) throws CommandSyntaxException
|
||||
{
|
||||
CarpetScriptHost currentHost = getHost(context);
|
||||
String previous = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
|
||||
@@ -291,7 +292,7 @@ public class ScriptCommand
|
||||
)?1:0)))))).
|
||||
then(literal("remove_from").
|
||||
then(argument("event", StringArgumentType.word()).
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.publicEvents(CarpetServer.scriptServer).stream().map(ev -> ev.name).collect(Collectors.toList()) ,bb)).
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.publicEvents(CarpetServer.scriptServer).stream().filter(CarpetEventServer.Event::isNeeded).map(ev -> ev.name).collect(Collectors.toList()) ,bb)).
|
||||
then(argument("call", StringArgumentType.greedyString()).
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.getEvent(StringArgumentType.getString(cc, "event"), CarpetServer.scriptServer).handler.callList.stream().map(CarpetEventServer.Callback::toString), bb)).
|
||||
executes( (cc) -> CarpetServer.scriptServer.events.removeEventFromCommand(
|
||||
@@ -311,14 +312,14 @@ public class ScriptCommand
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.modules.keySet(), bb)).
|
||||
then(b).then(u).then(o).then(l).then(s).then(c).then(h).then(i).then(e).then(t))));
|
||||
}
|
||||
private static CarpetScriptHost getHost(CommandContext<ServerCommandSource> context)
|
||||
private static CarpetScriptHost getHost(CommandContext<ServerCommandSource> context) throws CommandSyntaxException
|
||||
{
|
||||
CarpetScriptHost host;
|
||||
try
|
||||
{
|
||||
String name = StringArgumentType.getString(context, "app").toLowerCase(Locale.ROOT);
|
||||
CarpetScriptHost parentHost = CarpetServer.scriptServer.modules.getOrDefault(name, CarpetServer.scriptServer.globalHost);
|
||||
host = parentHost.retrieveForExecution(context.getSource());
|
||||
host = parentHost.retrieveOwnForExecution(context.getSource());
|
||||
}
|
||||
catch (IllegalArgumentException ignored)
|
||||
{
|
||||
@@ -327,7 +328,7 @@ public class ScriptCommand
|
||||
host.setChatErrorSnooper(context.getSource());
|
||||
return host;
|
||||
}
|
||||
private static Collection<String> suggestFunctionCalls(CommandContext<ServerCommandSource> c)
|
||||
private static Collection<String> suggestFunctionCalls(CommandContext<ServerCommandSource> c) throws CommandSyntaxException
|
||||
{
|
||||
CarpetScriptHost host = getHost(c);
|
||||
return host.globaFunctionNames(host.main, s -> !s.startsWith("_")).sorted().collect(Collectors.toList());
|
||||
@@ -350,7 +351,7 @@ public class ScriptCommand
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
private static int listGlobals(CommandContext<ServerCommandSource> context, boolean all)
|
||||
private static int listGlobals(CommandContext<ServerCommandSource> context, boolean all) throws CommandSyntaxException
|
||||
{
|
||||
CarpetScriptHost host = getHost(context);
|
||||
ServerCommandSource source = context.getSource();
|
||||
@@ -425,7 +426,7 @@ public class ScriptCommand
|
||||
//host.resetErrorSnooper(); // lets say no need to reset the snooper in case something happens on the way
|
||||
}
|
||||
|
||||
private static int invoke(CommandContext<ServerCommandSource> context, String call, BlockPos pos1, BlockPos pos2, String args)
|
||||
private static int invoke(CommandContext<ServerCommandSource> context, String call, BlockPos pos1, BlockPos pos2, String args) throws CommandSyntaxException
|
||||
{
|
||||
ServerCommandSource source = context.getSource();
|
||||
CarpetScriptHost host = getHost(context);
|
||||
@@ -453,7 +454,7 @@ public class ScriptCommand
|
||||
}
|
||||
|
||||
|
||||
private static int compute(CommandContext<ServerCommandSource> context, String expr)
|
||||
private static int compute(CommandContext<ServerCommandSource> context, String expr) throws CommandSyntaxException
|
||||
{
|
||||
ServerCommandSource source = context.getSource();
|
||||
CarpetScriptHost host = getHost(context);
|
||||
@@ -463,7 +464,7 @@ public class ScriptCommand
|
||||
});
|
||||
}
|
||||
|
||||
private static int scriptScan(CommandContext<ServerCommandSource> context, BlockPos origin, BlockPos a, BlockPos b, String expr)
|
||||
private static int scriptScan(CommandContext<ServerCommandSource> context, BlockPos origin, BlockPos a, BlockPos b, String expr) throws CommandSyntaxException
|
||||
{
|
||||
ServerCommandSource source = context.getSource();
|
||||
CarpetScriptHost host = getHost(context);
|
||||
@@ -512,7 +513,7 @@ public class ScriptCommand
|
||||
|
||||
|
||||
private static int scriptFill(CommandContext<ServerCommandSource> context, BlockPos origin, BlockPos a, BlockPos b, String expr,
|
||||
BlockStateArgument block, Predicate<CachedBlockPosition> replacement, String mode)
|
||||
BlockStateArgument block, Predicate<CachedBlockPosition> replacement, String mode) throws CommandSyntaxException
|
||||
{
|
||||
ServerCommandSource source = context.getSource();
|
||||
CarpetScriptHost host = getHost(context);
|
||||
|
||||
@@ -14,6 +14,7 @@ import carpet.script.value.Value;
|
||||
import carpet.script.value.ValueConversions;
|
||||
import carpet.settings.ParsedRule;
|
||||
import carpet.utils.Messenger;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
@@ -47,8 +48,9 @@ import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -65,59 +67,84 @@ public class CarpetEventServer
|
||||
public static class Callback
|
||||
{
|
||||
public final String host;
|
||||
public final String optionalTarget;
|
||||
public final FunctionValue function;
|
||||
public final List<Value> parametrizedArgs;
|
||||
|
||||
|
||||
public Callback(String host, FunctionValue function, List<Value> parametrizedArgs)
|
||||
public Callback(String host, String target, FunctionValue function, List<Value> parametrizedArgs)
|
||||
{
|
||||
this.host = host;
|
||||
this.function = function;
|
||||
this.optionalTarget = target;
|
||||
this.parametrizedArgs = parametrizedArgs==null?NOARGS:parametrizedArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used also in entity events
|
||||
* @param asSource - entity command source
|
||||
* @param sender - entity command source
|
||||
* @param runtimeArgs = options
|
||||
*/
|
||||
public boolean execute(ServerCommandSource asSource, List<Value> runtimeArgs)
|
||||
public boolean execute(ServerCommandSource sender, List<Value> runtimeArgs)
|
||||
{
|
||||
if (this.parametrizedArgs.isEmpty())
|
||||
return CarpetServer.scriptServer.runas(
|
||||
asSource.withLevel(CarpetSettings.runPermissionLevel),
|
||||
host, function, runtimeArgs);
|
||||
else
|
||||
if (!this.parametrizedArgs.isEmpty())
|
||||
{
|
||||
List<Value> combinedArgs = new ArrayList<>(runtimeArgs);
|
||||
combinedArgs.addAll(this.parametrizedArgs);
|
||||
return CarpetServer.scriptServer.runas(
|
||||
asSource.withLevel(CarpetSettings.runPermissionLevel),
|
||||
host, function, combinedArgs);
|
||||
runtimeArgs = new ArrayList<>(runtimeArgs);
|
||||
runtimeArgs.addAll(this.parametrizedArgs);
|
||||
}
|
||||
return CarpetServer.scriptServer.runEventCall(
|
||||
sender.withLevel(CarpetSettings.runPermissionLevel),
|
||||
host, optionalTarget, function, runtimeArgs
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used also in entity events
|
||||
* @param recipient - optional target player argument
|
||||
* @param sender - sender of the signal
|
||||
* @param optionalRecipient - optional target player argument
|
||||
* @param runtimeArgs = options
|
||||
*/
|
||||
public Boolean targetPlayer(ServerPlayerEntity recipient, List<Value> runtimeArgs)
|
||||
public int signal(ServerCommandSource sender, ServerPlayerEntity optionalRecipient, List<Value> runtimeArgs)
|
||||
{
|
||||
// recipent of the call doesn't match the handlingHost
|
||||
if (optionalRecipient != null && !optionalRecipient.getEntityName().equals(optionalTarget))
|
||||
return 0;
|
||||
List<Value> args = runtimeArgs;
|
||||
if (!this.parametrizedArgs.isEmpty())
|
||||
{
|
||||
args = new ArrayList<>(runtimeArgs);
|
||||
args.addAll(this.parametrizedArgs);
|
||||
}
|
||||
return CarpetServer.scriptServer.runForPlayer(recipient, host, function, args);
|
||||
return CarpetServer.scriptServer.signal(sender, optionalRecipient, host, function, args, false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return function.getString()+((host==null)?"":"(from "+host+")");
|
||||
return function.getString()+((host==null)?"":"(from "+host+(optionalTarget == null?"":"/"+optionalTarget)+")");
|
||||
}
|
||||
public static class Signature
|
||||
{
|
||||
String function;
|
||||
String host;
|
||||
String target;
|
||||
public Signature(String fun, String h, String t)
|
||||
{
|
||||
function = fun;
|
||||
host = h;
|
||||
target = t;
|
||||
}
|
||||
}
|
||||
public static Signature fromString(String str)
|
||||
{
|
||||
Pattern find = Pattern.compile("(\\w+)(?:\\(from (\\w+)(?:/(\\w+))?\\))?");
|
||||
Matcher matcher = find.matcher(str);
|
||||
if(matcher.matches())
|
||||
{
|
||||
return new Signature(matcher.group(1), matcher.group(2), matcher.group(3));
|
||||
}
|
||||
return new Signature(str, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +156,8 @@ public class CarpetEventServer
|
||||
|
||||
public ScheduledCall(CarpetContext context, FunctionValue function, List<Value> args, long dueTime)
|
||||
{
|
||||
super(context.host.getName(), function, args);
|
||||
// ignoring target as we will be always calling self
|
||||
super(context.host.getName(), null, function, args);
|
||||
this.ctx = context;
|
||||
this.dueTime = dueTime;
|
||||
}
|
||||
@@ -139,7 +167,7 @@ public class CarpetEventServer
|
||||
*/
|
||||
public void execute()
|
||||
{
|
||||
CarpetServer.scriptServer.runas(ctx.origin, ctx.s, host, function, parametrizedArgs);
|
||||
CarpetServer.scriptServer.runScheduledCall(ctx.origin, ctx.s, host, (CarpetScriptHost) ctx.host, function, parametrizedArgs);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +201,7 @@ public class CarpetEventServer
|
||||
}
|
||||
}
|
||||
|
||||
public int callCustom(ServerPlayerEntity receipient, List<Value> callArg)
|
||||
public int signal(ServerCommandSource sender, ServerPlayerEntity optinoalReceipient, List<Value> callArg)
|
||||
{
|
||||
if (callList.isEmpty()) return 0;
|
||||
//List<Callback> fails = new ArrayList<>();
|
||||
@@ -181,15 +209,13 @@ public class CarpetEventServer
|
||||
int successes = 0;
|
||||
for (Callback call: callList)
|
||||
{
|
||||
Boolean result = call.targetPlayer(receipient, callArg);
|
||||
//if (result == Boolean.FALSE) fails.add(call);
|
||||
if (result == Boolean.TRUE) successes++;
|
||||
successes += Math.max(0, call.signal(sender, optinoalReceipient, callArg));
|
||||
}
|
||||
//for (Callback call : fails) callList.remove(call);
|
||||
return successes;
|
||||
}
|
||||
|
||||
public boolean addEventCall(ServerCommandSource source, String hostName, String funName, Function<ScriptHost, Boolean> verifier)
|
||||
public boolean addFromExternal(ServerCommandSource source, String hostName, String funName, Consumer<ScriptHost> hostOnEventHandler)
|
||||
{
|
||||
ScriptHost host = CarpetServer.scriptServer.getHostByName(hostName);
|
||||
if (host == null)
|
||||
@@ -198,11 +224,7 @@ public class CarpetEventServer
|
||||
Messenger.m(source, "r Unknown app "+hostName);
|
||||
return false;
|
||||
}
|
||||
if (!verifier.apply(host))
|
||||
{
|
||||
Messenger.m(source, "r Global event can only be added to apps with global scope");
|
||||
return false;
|
||||
}
|
||||
hostOnEventHandler.accept(host);
|
||||
FunctionValue udf = host.getFunction(funName);
|
||||
if (udf == null || udf.getArguments().size() != reqArgs)
|
||||
{
|
||||
@@ -210,11 +232,24 @@ public class CarpetEventServer
|
||||
Messenger.m(source, "r Callback doesn't expect required number of arguments: "+reqArgs);
|
||||
return false;
|
||||
}
|
||||
String target = null;
|
||||
if (host.isPerUser())
|
||||
{
|
||||
try
|
||||
{
|
||||
target = source.getPlayer().getEntityName();
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
{
|
||||
Messenger.m(source, "r Cannot add event to a player scoped app from a command without a player context");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//all clear
|
||||
//remove duplicates
|
||||
|
||||
removeEventCall(hostName, udf.getString());
|
||||
callList.add(new Callback(hostName, udf, null));
|
||||
removeEventCall(hostName, target, udf.getString());
|
||||
callList.add(new Callback(hostName, target, udf, null));
|
||||
return true;
|
||||
}
|
||||
public boolean addEventCallInternal(ScriptHost host, FunctionValue function, List<Value> args)
|
||||
@@ -225,20 +260,39 @@ public class CarpetEventServer
|
||||
}
|
||||
//all clear
|
||||
//remove duplicates
|
||||
removeEventCall(host.getName(), function.getString());
|
||||
callList.add(new Callback(host.getName(), function, args));
|
||||
removeEventCall(host.getName(), host.user, function.getString());
|
||||
callList.add(new Callback(host.getName(), host.user, function, args));
|
||||
return true;
|
||||
}
|
||||
|
||||
public void removeEventCall(String hostName, String funName)
|
||||
public void removeEventCall(String hostName, String target, String funName)
|
||||
{
|
||||
callList.removeIf((c)-> c.function.getString().equals(funName) && ( hostName == c.host || (c.host != null && c.host.equalsIgnoreCase(hostName) )) );
|
||||
callList.removeIf((c)-> c.function.getString().equals(funName)
|
||||
&& (Objects.equals(c.host, hostName))
|
||||
&& (Objects.equals(c.optionalTarget, target))
|
||||
);
|
||||
}
|
||||
|
||||
public void removeAllCalls(CarpetScriptHost host)
|
||||
{
|
||||
callList.removeIf((c)-> c.host != null && c.host.equals(host.getName()));
|
||||
callList.removeIf((c)-> (Objects.equals(c.host, host.getName()))
|
||||
&& (Objects.equals(c.optionalTarget, host.user)));
|
||||
}
|
||||
|
||||
public void createChildEvents(CarpetScriptHost host)
|
||||
{
|
||||
List<Callback> copyCalls = new ArrayList<>();
|
||||
callList.forEach((c)->
|
||||
{
|
||||
if ((Objects.equals(c.host, host.getName()))
|
||||
&& c.optionalTarget == null)
|
||||
{
|
||||
copyCalls.add(new Callback(c.host, host.user, c.function, c.parametrizedArgs));
|
||||
}
|
||||
});
|
||||
callList.addAll(copyCalls);
|
||||
}
|
||||
|
||||
public void clearEverything()
|
||||
{
|
||||
callList.clear();
|
||||
@@ -801,6 +855,12 @@ public class CarpetEventServer
|
||||
host.getScriptServer().events.customEvents.values().forEach((e) -> e.handler.removeAllCalls(host));
|
||||
}
|
||||
|
||||
public static void transferAllHostEventsToChild(CarpetScriptHost host)
|
||||
{
|
||||
byName.values().forEach((e) -> e.handler.createChildEvents(host));
|
||||
host.getScriptServer().events.customEvents.values().forEach((e) -> e.handler.createChildEvents(host));
|
||||
}
|
||||
|
||||
public static void clearAllBuiltinEvents()
|
||||
{
|
||||
byName.values().forEach(e -> e.handler.clearEverything());
|
||||
@@ -888,7 +948,7 @@ public class CarpetEventServer
|
||||
{
|
||||
return false;
|
||||
}
|
||||
boolean added = ev.handler.addEventCall(source, host, funName, h -> canAddEvent(ev, h));
|
||||
boolean added = ev.handler.addFromExternal(source, host, funName, h -> onEventAddedToHost(ev, h));
|
||||
if (added) Messenger.m(source, "gi Added " + funName + " to " + event);
|
||||
return added;
|
||||
}
|
||||
@@ -897,8 +957,7 @@ public class CarpetEventServer
|
||||
{
|
||||
// this is globals only
|
||||
Event ev = Event.byName.get(event);
|
||||
if (!canAddEvent(ev, host))
|
||||
throw new InternalExpressionException("Global event "+event+" can only be added to apps with global scope");
|
||||
onEventAddedToHost(ev, host);
|
||||
boolean success = ev.handler.addEventCallInternal(host, function, args==null?NOARGS:args);
|
||||
if (!success) throw new InternalExpressionException("Global event "+event+" requires "+ev.handler.reqArgs+", not "+(function.getNumParams()-((args==null)?0:args.size())));
|
||||
}
|
||||
@@ -906,22 +965,21 @@ public class CarpetEventServer
|
||||
public boolean handleCustomEvent(String event, CarpetScriptHost host, FunctionValue function, List<Value> args)
|
||||
{
|
||||
Event ev = Event.getOrCreateCustom(event, host.getScriptServer());
|
||||
if (!canAddEvent(ev, host))
|
||||
throw new InternalExpressionException("Global built-in event "+event+" can only be handled in apps with global scope");
|
||||
onEventAddedToHost(ev, host);
|
||||
return ev.handler.addEventCallInternal(host, function, args==null?NOARGS:args);
|
||||
}
|
||||
|
||||
public int signalEvent(String event, CarpetScriptHost host, ServerPlayerEntity player, List<Value> callArgs)
|
||||
public int signalEvent(String event, CarpetContext cc, ServerPlayerEntity optionalTarget, List<Value> callArgs)
|
||||
{
|
||||
Event ev = Event.getEvent(event, host.getScriptServer());
|
||||
Event ev = Event.getEvent(event, ((CarpetScriptHost)cc.host).getScriptServer());
|
||||
if (ev == null) return -1;
|
||||
return ev.handler.callCustom(player, callArgs);
|
||||
return ev.handler.signal(cc.s, optionalTarget, callArgs);
|
||||
}
|
||||
|
||||
private boolean canAddEvent(Event event, ScriptHost host)
|
||||
private void onEventAddedToHost(Event event, ScriptHost host)
|
||||
{
|
||||
if (event.deprecated()) host.issueDeprecation(event.name+" event");
|
||||
return !(event.globalOnly && (host.perUser || host.parent != null));
|
||||
//return !(event.globalOnly && (host.perUser || host.parent != null));
|
||||
}
|
||||
|
||||
public boolean removeEventFromCommand(ServerCommandSource source, String event, String funName)
|
||||
@@ -932,8 +990,8 @@ public class CarpetEventServer
|
||||
Messenger.m(source, "r Unknown event: " + event);
|
||||
return false;
|
||||
}
|
||||
Pair<String,String> call = decodeCallback(funName);
|
||||
ev.handler.removeEventCall(call.getLeft(), call.getRight());
|
||||
Callback.Signature call = Callback.fromString(funName);
|
||||
ev.handler.removeEventCall(call.host, call.target, call.function);
|
||||
// could verified if actually removed
|
||||
Messenger.m(source, "gi Removed event: " + funName + " from "+event);
|
||||
return true;
|
||||
@@ -949,13 +1007,15 @@ public class CarpetEventServer
|
||||
public void removeBuiltInEvent(String event, CarpetScriptHost host, String funName)
|
||||
{
|
||||
Event ev = Event.getEvent(event, host.getScriptServer());
|
||||
if (ev != null) ev.handler.removeEventCall(host.getName(), funName);
|
||||
if (ev != null) ev.handler.removeEventCall(host.getName(), host.user, funName);
|
||||
}
|
||||
|
||||
public void removeAllHostEvents(CarpetScriptHost host)
|
||||
{
|
||||
// remove event handlers
|
||||
Event.removeAllHostEvents(host);
|
||||
if (host.isPerUser())
|
||||
for (ScriptHost child: host.userHosts.values()) Event.removeAllHostEvents((CarpetScriptHost) child);
|
||||
// remove scheduled calls
|
||||
scheduledCalls.removeIf(sc -> sc.host != null && sc.host.equals(host.getName()));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package carpet.script;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.script.api.Auxiliary;
|
||||
import carpet.script.argument.FunctionArgument;
|
||||
import carpet.script.bundled.Module;
|
||||
@@ -15,7 +16,6 @@ import carpet.script.value.MapValue;
|
||||
import carpet.script.value.NumericValue;
|
||||
import carpet.script.value.StringValue;
|
||||
import carpet.script.value.Value;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.utils.Messenger;
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
@@ -117,7 +117,7 @@ public class CarpetScriptHost extends ScriptHost
|
||||
|
||||
private static int execute(CommandContext<ServerCommandSource> ctx, String hostName, FunctionArgument<Value> funcSpec, List<String> paramNames) throws CommandSyntaxException
|
||||
{
|
||||
CarpetScriptHost cHost = CarpetServer.scriptServer.modules.get(hostName).retrieveForExecution(ctx.getSource());
|
||||
CarpetScriptHost cHost = CarpetServer.scriptServer.modules.get(hostName).retrieveOwnForExecution(ctx.getSource());
|
||||
List<String> argNames = funcSpec.function.getArguments();
|
||||
if ((argNames.size()-funcSpec.args.size()) != paramNames.size())
|
||||
throw new SimpleCommandExceptionType(new LiteralText("Target function "+funcSpec.function.getPrettyString()+" as wrong number of arguments, required "+paramNames.size()+", found "+argNames.size()+" with "+funcSpec.args.size()+" provided")).create();
|
||||
@@ -177,6 +177,14 @@ public class CarpetScriptHost extends ScriptHost
|
||||
return new CarpetScriptHost(scriptServer, main, false, this, appConfig, appArgTypes, commandValidator, isRuleApp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void transferToChild(ScriptHost host)
|
||||
{
|
||||
super.transferToChild(host);
|
||||
// transfer Events
|
||||
CarpetEventServer.Event.transferAllHostEventsToChild((CarpetScriptHost) host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUserDefinedFunction(Context ctx, Module module, String funName, FunctionValue function)
|
||||
{
|
||||
@@ -319,38 +327,58 @@ public class CarpetScriptHost extends ScriptHost
|
||||
}
|
||||
}
|
||||
|
||||
public CarpetScriptHost retrieveForExecution(ServerCommandSource source)
|
||||
public List<CarpetScriptHost> retrieveForExecution(ServerCommandSource source, String optionalTarget)
|
||||
{
|
||||
CarpetScriptHost host = this;
|
||||
List<CarpetScriptHost> targets = new ArrayList<>();
|
||||
if (perUser)
|
||||
{
|
||||
try
|
||||
if (optionalTarget == null)
|
||||
{
|
||||
ServerPlayerEntity player = source.getPlayer();
|
||||
host = (CarpetScriptHost) retrieveForExecution(player.getName().getString());
|
||||
for (ServerPlayerEntity player : source.getMinecraftServer().getPlayerManager().getPlayerList())
|
||||
{
|
||||
CarpetScriptHost host = (CarpetScriptHost) retrieveForExecution(player.getEntityName());
|
||||
targets.add(host);
|
||||
if (host.errorSnooper == null) host.setChatErrorSnooper(player.getCommandSource());
|
||||
}
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
else
|
||||
{
|
||||
host = (CarpetScriptHost) retrieveForExecution((String) null);
|
||||
ServerPlayerEntity player = source.getMinecraftServer().getPlayerManager().getPlayer(optionalTarget);
|
||||
if (player != null)
|
||||
{
|
||||
CarpetScriptHost host = (CarpetScriptHost) retrieveForExecution(player.getEntityName());
|
||||
targets.add(host);
|
||||
if (host.errorSnooper == null) host.setChatErrorSnooper(player.getCommandSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (host.errorSnooper == null) host.setChatErrorSnooper(source);
|
||||
return host;
|
||||
else
|
||||
{
|
||||
targets.add(this);
|
||||
if (this.errorSnooper == null) this.setChatErrorSnooper(source);
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
public CarpetScriptHost retrieveForExecution(ServerPlayerEntity target)
|
||||
public CarpetScriptHost retrieveOwnForExecution(ServerCommandSource source) throws CommandSyntaxException
|
||||
{
|
||||
// allowing only run
|
||||
if (perUser == (target == null)) return null;
|
||||
|
||||
if (!perUser)
|
||||
{
|
||||
if (errorSnooper == null) setChatErrorSnooper(this.scriptServer.server.getCommandSource());
|
||||
if (errorSnooper == null) setChatErrorSnooper(source);
|
||||
return this;
|
||||
}
|
||||
// user based
|
||||
CarpetScriptHost userHost = (CarpetScriptHost)retrieveForExecution(target.getName().getString());
|
||||
if (userHost.errorSnooper == null) userHost.setChatErrorSnooper(target.getCommandSource());
|
||||
ServerPlayerEntity player;
|
||||
try
|
||||
{
|
||||
player = source.getPlayer();
|
||||
}
|
||||
catch (CommandSyntaxException ignored)
|
||||
{
|
||||
throw new SimpleCommandExceptionType(new LiteralText("Cannot run player based apps without the player context")).create();
|
||||
}
|
||||
CarpetScriptHost userHost = (CarpetScriptHost)retrieveForExecution(player.getEntityName());
|
||||
if (userHost.errorSnooper == null) userHost.setChatErrorSnooper(source);
|
||||
return userHost;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package carpet.script;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.script.argument.FunctionArgument;
|
||||
import carpet.script.bundled.BundledModule;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.CarpetServer;
|
||||
import carpet.script.bundled.FileModule;
|
||||
import carpet.script.bundled.Module;
|
||||
@@ -296,6 +296,11 @@ public class CarpetScriptServer
|
||||
Messenger.m(source, "r Failed to build command system for "+name+" thus failed to load the app");
|
||||
return false;
|
||||
}
|
||||
if (newHost.isPerUser())
|
||||
{
|
||||
// that will provide player hosts right at the startup
|
||||
newHost.retrieveForExecution(source, null);
|
||||
}
|
||||
long end = System.nanoTime();
|
||||
CarpetSettings.LOG.info("App "+name+" loaded in "+(end-start)/1000000+" ms");
|
||||
return true;
|
||||
@@ -325,8 +330,8 @@ public class CarpetScriptServer
|
||||
requires((player) -> modules.containsKey(hostName) && useValidator.apply(player)).
|
||||
executes( (c) ->
|
||||
{
|
||||
Value response = modules.get(hostName).retrieveForExecution(c.getSource()).
|
||||
handleCommandLegacy(c.getSource(),"__command", null, "");
|
||||
CarpetScriptHost targetHost = modules.get(hostName).retrieveOwnForExecution(c.getSource());
|
||||
Value response = targetHost.handleCommandLegacy(c.getSource(),"__command", null, "");
|
||||
if (!response.isNull()) Messenger.m(c.getSource(), "gi "+response.getString());
|
||||
return (int)response.readInteger();
|
||||
});
|
||||
@@ -355,15 +360,15 @@ public class CarpetScriptServer
|
||||
then(literal(function).
|
||||
requires((player) -> modules.containsKey(hostName) && modules.get(hostName).getFunction(function) != null).
|
||||
executes((c) -> {
|
||||
Value response = modules.get(hostName).retrieveForExecution(c.getSource()).
|
||||
handleCommandLegacy(c.getSource(), function, null, "");
|
||||
CarpetScriptHost targetHost = modules.get(hostName).retrieveOwnForExecution(c.getSource());
|
||||
Value response = targetHost.handleCommandLegacy(c.getSource(),function, null, "");
|
||||
if (!response.isNull()) Messenger.m(c.getSource(), "gi " + response.getString());
|
||||
return (int) response.readInteger();
|
||||
}).
|
||||
then(argument("args...", StringArgumentType.greedyString()).
|
||||
executes( (c) -> {
|
||||
Value response = modules.get(hostName).retrieveForExecution(c.getSource()).
|
||||
handleCommandLegacy(c.getSource(), function,null, StringArgumentType.getString(c, "args..."));
|
||||
CarpetScriptHost targetHost = modules.get(hostName).retrieveOwnForExecution(c.getSource());
|
||||
Value response = targetHost.handleCommandLegacy(c.getSource(),function, null, StringArgumentType.getString(c, "args..."));
|
||||
if (!response.isNull()) Messenger.m(c.getSource(), "gi "+response.getString());
|
||||
return (int)response.readInteger();
|
||||
})));
|
||||
@@ -394,54 +399,84 @@ public class CarpetScriptServer
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean runas(ServerCommandSource source, String hostname, FunctionValue udf, List<Value> argv)
|
||||
{
|
||||
return runas(BlockPos.ORIGIN, source, hostname, udf, argv);
|
||||
}
|
||||
|
||||
public boolean runas(BlockPos origin, ServerCommandSource source, String hostname, FunctionValue udf, List<Value> argv)
|
||||
public boolean runEventCall(ServerCommandSource sender, String hostname, String optionalTarget, FunctionValue udf, List<Value> argv)
|
||||
{
|
||||
CarpetScriptHost host = globalHost;
|
||||
try
|
||||
if (hostname != null)
|
||||
host = modules.get(hostname);
|
||||
if (host == null) return false;
|
||||
// dummy call for player apps that reside on the global copy - do not run them, but report as successes.
|
||||
if (host.isPerUser() && optionalTarget==null) return true;
|
||||
ServerPlayerEntity target = null;
|
||||
if (optionalTarget != null)
|
||||
{
|
||||
if (hostname != null)
|
||||
host = modules.get(hostname).retrieveForExecution(source);
|
||||
host.callUDF(origin, source, udf, argv);
|
||||
target = sender.getMinecraftServer().getPlayerManager().getPlayer(optionalTarget);
|
||||
if (target == null) return false;
|
||||
}
|
||||
catch (NullPointerException | InvalidCallbackException npe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
int successes = signal(sender, target, hostname, udf, argv, true );
|
||||
return successes >= 0;
|
||||
}
|
||||
|
||||
public Boolean runForPlayer(ServerPlayerEntity recipient, String hostname, FunctionValue udf, List<Value> argv)
|
||||
public void runScheduledCall(BlockPos origin, ServerCommandSource source, String hostname, CarpetScriptHost host, FunctionValue udf, List<Value> argv)
|
||||
{
|
||||
if (hostname != null && !modules.containsKey(hostname)) // well - scheduled call app got unloaded
|
||||
return;
|
||||
try
|
||||
{
|
||||
host.callUDF(origin, source, udf, argv);
|
||||
}
|
||||
catch (NullPointerException | InvalidCallbackException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns number of successful calls in the host or -1 if failed exceptionally
|
||||
* @param sender
|
||||
* @param optionalRecipient
|
||||
* @param hostname
|
||||
* @param udf
|
||||
* @param argv
|
||||
* @param reportFails - returns -1 when any call failed
|
||||
* @return
|
||||
*/
|
||||
public int signal(ServerCommandSource sender, ServerPlayerEntity optionalRecipient, String hostname, FunctionValue udf, List<Value> argv, boolean reportFails)
|
||||
{
|
||||
CarpetScriptHost host;
|
||||
ServerCommandSource source;
|
||||
|
||||
if (hostname == null)
|
||||
{
|
||||
if (recipient != null) return null;
|
||||
host = globalHost;
|
||||
source = server.getCommandSource();
|
||||
if (optionalRecipient != null) return 0;
|
||||
try
|
||||
{
|
||||
globalHost.callUDF(BlockPos.ORIGIN, sender, udf, argv);
|
||||
}
|
||||
catch (NullPointerException | InvalidCallbackException npe)
|
||||
{
|
||||
return reportFails?-1:0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
String hostRecipient = optionalRecipient == null?null:optionalRecipient.getEntityName();
|
||||
ServerCommandSource source = (optionalRecipient == null)? sender : optionalRecipient.getCommandSource().withLevel(CarpetSettings.runPermissionLevel);
|
||||
int successes = 0;
|
||||
for (CarpetScriptHost host : modules.get(hostname).retrieveForExecution(sender, hostRecipient))
|
||||
{
|
||||
host = modules.get(hostname).retrieveForExecution(recipient);
|
||||
if (host == null) // not applicable
|
||||
return null;
|
||||
source = (recipient == null)? server.getCommandSource() : recipient.getCommandSource();
|
||||
// getPlayer will always return nonnull cause retrieve for execution only returns hosts for existing players.
|
||||
ServerCommandSource executingSource = host.perUser
|
||||
? source.getMinecraftServer().getPlayerManager().getPlayer(host.user).getCommandSource()
|
||||
: source.getMinecraftServer().getCommandSource();
|
||||
try
|
||||
{
|
||||
host.callUDF(BlockPos.ORIGIN, source.withLevel(CarpetSettings.runPermissionLevel), udf, argv);
|
||||
}
|
||||
catch (NullPointerException | InvalidCallbackException npe)
|
||||
{
|
||||
if (reportFails) return -1;
|
||||
continue;
|
||||
}
|
||||
successes ++;
|
||||
}
|
||||
try
|
||||
{
|
||||
host.callUDF(BlockPos.ORIGIN, source.withLevel(CarpetSettings.runPermissionLevel), udf, argv);
|
||||
}
|
||||
catch (NullPointerException | InvalidCallbackException npe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return successes;
|
||||
}
|
||||
|
||||
public void tick()
|
||||
@@ -461,6 +496,23 @@ public class CarpetScriptServer
|
||||
}
|
||||
}
|
||||
|
||||
public void onPlayerJoin(ServerPlayerEntity player)
|
||||
{
|
||||
modules.values().forEach(h ->
|
||||
{
|
||||
if (h.isPerUser())
|
||||
{
|
||||
try
|
||||
{
|
||||
h.retrieveOwnForExecution(player.getCommandSource());
|
||||
}
|
||||
catch (CommandSyntaxException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static class TransferData
|
||||
{
|
||||
boolean perUser;
|
||||
|
||||
@@ -9,6 +9,7 @@ import carpet.script.value.StringValue;
|
||||
import carpet.script.value.Value;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -19,7 +20,7 @@ import java.util.Map;
|
||||
|
||||
public class EntityEventsGroup
|
||||
{
|
||||
private final Map<Event, Map<String, CarpetEventServer.Callback>> actions;
|
||||
private final Map<Event, Map<Pair<String,String>, CarpetEventServer.Callback>> actions;
|
||||
private final Entity entity;
|
||||
public EntityEventsGroup(Entity e)
|
||||
{
|
||||
@@ -30,37 +31,47 @@ public class EntityEventsGroup
|
||||
public void onEvent(Event type, Object... args)
|
||||
{
|
||||
if (actions.isEmpty()) return; // most of the cases, trying to be nice
|
||||
Map<String, CarpetEventServer.Callback> actionSet = actions.get(type);
|
||||
Map<Pair<String,String>, CarpetEventServer.Callback> actionSet = actions.get(type);
|
||||
if (actionSet == null) return;
|
||||
|
||||
|
||||
for (Iterator<Map.Entry<String, CarpetEventServer.Callback>> iterator = actionSet.entrySet().iterator(); iterator.hasNext(); )
|
||||
for (Iterator<Map.Entry<Pair<String,String>, CarpetEventServer.Callback>> iterator = actionSet.entrySet().iterator(); iterator.hasNext(); )
|
||||
{
|
||||
Map.Entry<String, CarpetEventServer.Callback> action = iterator.next();
|
||||
ScriptHost host = CarpetServer.scriptServer.getHostByName(action.getKey());
|
||||
Map.Entry<Pair<String,String>, CarpetEventServer.Callback> action = iterator.next();
|
||||
Pair<String,String> key = action.getKey();
|
||||
ScriptHost host = CarpetServer.scriptServer.getHostByName(key.getLeft());
|
||||
if (host == null)
|
||||
{
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
if (key.getRight() != null)
|
||||
{
|
||||
if (entity.getServer().getPlayerManager().getPlayer(key.getRight())==null)
|
||||
{
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!type.call(action.getValue(), entity, args))
|
||||
iterator.remove();
|
||||
}
|
||||
if (actionSet.isEmpty()) actions.remove(type);
|
||||
}
|
||||
|
||||
public void addEvent(Event type, String hostName, FunctionValue fun, List<Value> extraargs)
|
||||
public void addEvent(Event type, ScriptHost host, FunctionValue fun, List<Value> extraargs)
|
||||
{
|
||||
Pair<String,String> key = Pair.of(host.getName(), host.user);
|
||||
if (fun != null)
|
||||
{
|
||||
CarpetEventServer.Callback call = type.create(hostName, fun, extraargs);
|
||||
CarpetEventServer.Callback call = type.create(key, fun, extraargs);
|
||||
if (call == null)
|
||||
throw new InternalExpressionException("wrong number of arguments for callback, required "+type.argcount);
|
||||
actions.computeIfAbsent(type, k -> new HashMap<>()).put(hostName, call);
|
||||
actions.computeIfAbsent(type, k -> new HashMap<>()).put(key, call);
|
||||
}
|
||||
else
|
||||
{
|
||||
actions.computeIfAbsent(type, k -> new HashMap<>()).remove(hostName);
|
||||
actions.computeIfAbsent(type, k -> new HashMap<>()).remove(key);
|
||||
if (actions.get(type).isEmpty())
|
||||
actions.remove(type);
|
||||
}
|
||||
@@ -107,13 +118,13 @@ public class EntityEventsGroup
|
||||
argcount = args+1; // entity is not extra
|
||||
byName.put(identifier, this);
|
||||
}
|
||||
public CarpetEventServer.Callback create(String hostName, FunctionValue function, List<Value> extraArgs)
|
||||
public CarpetEventServer.Callback create(Pair<String,String> key, FunctionValue function, List<Value> extraArgs)
|
||||
{
|
||||
if ((function.getArguments().size()-(extraArgs == null ? 0 : extraArgs.size())) != argcount)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new CarpetEventServer.Callback(hostName, function, extraArgs);
|
||||
return new CarpetEventServer.Callback(key.getLeft(), key.getRight(), function, extraArgs);
|
||||
}
|
||||
public boolean call(CarpetEventServer.Callback tickCall, Entity entity, Object ... args)
|
||||
{
|
||||
|
||||
@@ -318,15 +318,21 @@ public abstract class ScriptHost
|
||||
ScriptHost oldUserHost = userHosts.get(user);
|
||||
if (oldUserHost != null) return oldUserHost;
|
||||
ScriptHost userHost = this.duplicate();
|
||||
userHost.modules.putAll(this.modules);
|
||||
this.moduleData.forEach((key, value) -> userHost.moduleData.put(key, new ModuleData(key, value)));
|
||||
// fixing imports
|
||||
userHost.moduleData.forEach((module, data) -> data.setImportsBasedOn(userHost, this.moduleData.get(data.parent)));
|
||||
userHost.user = user;
|
||||
this.transferToChild(userHost);
|
||||
userHosts.put(user, userHost);
|
||||
return userHost;
|
||||
}
|
||||
|
||||
protected void transferToChild(ScriptHost host)
|
||||
{
|
||||
// adding imports
|
||||
host.modules.putAll(this.modules);
|
||||
this.moduleData.forEach((key, value) -> host.moduleData.put(key, new ModuleData(key, value)));
|
||||
// fixing imports
|
||||
host.moduleData.forEach((module, data) -> data.setImportsBasedOn(host, this.moduleData.get(data.parent)));
|
||||
}
|
||||
|
||||
public void handleExpressionException(String msg, ExpressionException exc)
|
||||
{
|
||||
System.out.println(msg+": "+exc);
|
||||
|
||||
@@ -961,6 +961,7 @@ public class Auxiliary {
|
||||
{
|
||||
if (lv.size() == 0)
|
||||
throw new InternalExpressionException("'signal' requires at least one argument");
|
||||
CarpetContext cc = (CarpetContext)c;
|
||||
CarpetScriptServer server = ((CarpetScriptHost)c.host).getScriptServer();
|
||||
String eventName = lv.get(0).evalValue(c).getString();
|
||||
// no such event yet
|
||||
@@ -975,10 +976,10 @@ public class Auxiliary {
|
||||
args = FunctionValue.resolveArgs(lv.subList(2, lv.size()), c, t);
|
||||
}
|
||||
}
|
||||
int counts = ((CarpetScriptHost)c.host).getScriptServer().events.signalEvent(eventName, (CarpetScriptHost) c.host, player, args);
|
||||
int counts = ((CarpetScriptHost)c.host).getScriptServer().events.signalEvent(eventName, cc, player, args);
|
||||
if (counts < 0) return LazyValue.NULL;
|
||||
Value ret = new NumericValue(counts);
|
||||
return (cc, tt) -> ret;
|
||||
return (c_, t_) -> ret;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1372,7 +1372,7 @@ public class EntityValue extends Value
|
||||
EntityEventsGroup.Event event = EntityEventsGroup.Event.byName.get(eventName);
|
||||
if (event == null)
|
||||
throw new InternalExpressionException("Unknown entity event: " + eventName);
|
||||
((EntityInterface)entity).getEventContainer().addEvent(event, cc.host.getName(), fun, args);
|
||||
((EntityInterface)entity).getEventContainer().addEvent(event, cc.host, fun, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -90,12 +90,9 @@ calculate(end)->(
|
||||
)
|
||||
);
|
||||
|
||||
_carpets() -> system_info('world_carpet_rules'):'carpets'=='true';
|
||||
|
||||
|
||||
on_player_places_block(player, item_tuple, hand, block) ->
|
||||
(
|
||||
if(block==global_assist_block && _carpets(),
|
||||
if(block==global_assist_block,
|
||||
effective_pos = pos(block)+[0.5, 0, 0.5];
|
||||
if(global_current_start==null||player~'sneaking',//wont complain for first carpet
|
||||
set_start(effective_pos)
|
||||
@@ -107,7 +104,7 @@ on_player_places_block(player, item_tuple, hand, block) ->
|
||||
|
||||
on_player_uses_item(player, item_tuple, hand) ->
|
||||
(
|
||||
if (item_tuple:0 == global_assist_block && hand == 'mainhand' && _carpets(),
|
||||
if (item_tuple:0 == global_assist_block && hand == 'mainhand',
|
||||
if (player ~'sneaking',
|
||||
global_current_mode = global_display_modes:(global_display_modes ~ global_current_mode + 1);
|
||||
display_title(player, 'actionbar', format('w Distance mode: ','e '+global_current_mode));
|
||||
|
||||
Reference in new issue
Block a user