Merge branch 'master' into 1.17

This commit is contained in:
gnembon committed 2020-12-02 13:23:32 -04:00
commit 0bacbcc2f5
18 files changed
+669 -349

No files matched your search

@@ -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)
{
+10 -4
View File
@@ -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;
});
}
@@ -12,6 +12,9 @@ import carpet.script.value.StringValue;
import carpet.script.value.FormattedTextValue;
import carpet.script.value.Value;
import net.minecraft.entity.Entity;
import net.minecraft.entity.boss.BossBar;
import net.minecraft.entity.boss.BossBarManager;
import net.minecraft.entity.boss.CommandBossBar;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.scoreboard.ServerScoreboard;
@@ -20,9 +23,12 @@ import net.minecraft.scoreboard.ScoreboardObjective;
import net.minecraft.scoreboard.ScoreboardPlayerScore;
import net.minecraft.scoreboard.Team;
import net.minecraft.scoreboard.AbstractTeam;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.minecraft.util.InvalidIdentifierException;
import java.util.stream.Collectors;
@@ -396,6 +402,131 @@ public class Scoreboards {
}
return LazyValue.TRUE;
});
expression.addLazyFunction("bossbar", -1, (c, t, lv) ->
{
BossBarManager bossBarManager = ((CarpetContext)c).s.getMinecraftServer().getBossBarManager();
if(lv.size() > 3) throw new InternalExpressionException("'bossbar' accepts max three arguments");
if(lv.size() == 0) {
Value ret = ListValue.wrap(bossBarManager.getAll().stream().map(CommandBossBar::getId).map(Identifier::toString).map(StringValue::of).collect(Collectors.toList()));
return (_c, _t) -> ret;
}
String id = lv.get(0).evalValue(c).getString();
Identifier identifier;
try {
identifier = new Identifier(id);
} catch (InvalidIdentifierException invalidIdentifierException) {
return LazyValue.NULL;
}
if(lv.size() == 1) {
if(bossBarManager.get(identifier) != null) return LazyValue.FALSE;
Value ret = StringValue.of(bossBarManager.add(identifier,new LiteralText(id)).getId().toString());
return (_c, _t) -> ret;
}
String property = lv.get(1).evalValue(c).getString();
CommandBossBar bossBar = bossBarManager.get(identifier);
if(bossBar == null) return LazyValue.NULL;
Value propertyValue = (lv.size() == 3)?lv.get(2).evalValue(c):null;
switch (property) {
case "color":
if(propertyValue == null) {
BossBar.Color color = (bossBar).getColor();
if(color == null) return LazyValue.NULL;
return (_c, _t) -> StringValue.of(color.getName());
}
BossBar.Color color = BossBar.Color.byName(propertyValue.getString());
if(color == null) return LazyValue.NULL;
bossBar.setColor(BossBar.Color.byName(propertyValue.getString()));
return LazyValue.TRUE;
case "max":
if(propertyValue == null) return (_c, _t) -> NumericValue.of(bossBar.getMaxValue());
if(!(propertyValue instanceof NumericValue)) throw new InternalExpressionException("'bossbar' requires a number as the value for the property " + property);
bossBar.setMaxValue(((NumericValue) propertyValue).getInt());
return LazyValue.TRUE;
case "name":
if(propertyValue == null) return (_c, _t) -> new FormattedTextValue(bossBar.getName());
if(propertyValue instanceof FormattedTextValue) {
bossBar.setName(((FormattedTextValue) propertyValue).getText());
} else {
bossBar.setName(new LiteralText(propertyValue.getString()));
}
return LazyValue.TRUE;
case "add_player":
if(propertyValue == null) throw new InternalExpressionException("Bossbar property " + property + " can't be queried, add a third parameter");
if(propertyValue instanceof ListValue) {
((ListValue) propertyValue).getItems().forEach((v)->{
ServerPlayerEntity player = EntityValue.getPlayerByValue(((CarpetContext)c).s.getMinecraftServer(),propertyValue);
if(player != null) bossBar.addPlayer(player);
});
return LazyValue.TRUE;
}
ServerPlayerEntity player = EntityValue.getPlayerByValue(((CarpetContext) c).s.getMinecraftServer(), propertyValue);
if(player != null) {
bossBar.addPlayer(player);
return LazyValue.TRUE;
}
return LazyValue.FALSE;
case "players":
if(propertyValue == null) {
return (_c, _t) -> ListValue.wrap(bossBar.getPlayers().stream().map(EntityValue::new).collect(Collectors.toList()));
}
if(propertyValue instanceof ListValue) {
bossBar.clearPlayers();
((ListValue) propertyValue).getItems().forEach((v) -> {
ServerPlayerEntity p = EntityValue.getPlayerByValue(((CarpetContext) c).s.getMinecraftServer(), v);
if (p != null) bossBar.addPlayer(p);
});
return LazyValue.TRUE;
}
ServerPlayerEntity p = EntityValue.getPlayerByValue(((CarpetContext) c).s.getMinecraftServer(), propertyValue);
bossBar.clearPlayers();
if (p != null) {
bossBar.addPlayer(p);
return LazyValue.TRUE;
}
return LazyValue.FALSE;
case "style":
if(propertyValue == null) {
return (_c, _t) -> StringValue.of(bossBar.getOverlay().getName());
}
BossBar.Style style = BossBar.Style.byName(propertyValue.getString());
if(style == null) throw new InternalExpressionException("'" + propertyValue.getString() + "' is not a valid value for property " + property);
bossBar.setOverlay(style);
return LazyValue.TRUE;
case "value":
if(propertyValue == null) return (_c, _t) -> NumericValue.of(bossBar.getValue());
if(!(propertyValue instanceof NumericValue)) throw new InternalExpressionException("'bossbar' requires a number as the value for the property " + property);
bossBar.setValue(((NumericValue) propertyValue).getInt());
return LazyValue.TRUE;
case "visible":
if(propertyValue == null) return (_c, _t) -> new NumericValue(bossBar.isVisible());
bossBar.setVisible(propertyValue.getBoolean());
return LazyValue.TRUE;
case "remove":
bossBarManager.remove(bossBar);
return LazyValue.TRUE;
default:
throw new InternalExpressionException("Unknown bossbar property " + property);
}
});
}
}
@@ -1387,7 +1387,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