Merge branch 'master' into 1.17

This commit is contained in:
gnembon committed 2020-11-11 02:08:05 -04:00
commit be3cb35f75
19 files changed
+744 -133

No files matched your search

@@ -105,7 +105,7 @@ public class PlayerCommand
.executes(c -> action(c, type, EntityPlayerActionPack.Action.once()))
.then(literal("once").executes(c -> action(c, type, EntityPlayerActionPack.Action.once())))
.then(literal("continuous").executes(c -> action(c, type, EntityPlayerActionPack.Action.continuous())))
.then(literal("interval").then(argument("ticks", IntegerArgumentType.integer(2))
.then(literal("interval").then(argument("ticks", IntegerArgumentType.integer(1))
.executes(c -> action(c, type, EntityPlayerActionPack.Action.interval(IntegerArgumentType.getInteger(c, "ticks"))))));
}
@@ -74,8 +74,8 @@ public class ScriptCommand
scarpetMatches.addAll(APIFunctions.stream().
filter(s -> s.startsWith(prefix) && s.length() <= maxLen).map(s -> s+"(").collect(Collectors.toList()));
// not that useful in commandline, more so in external scripts, so skipping here
if (eventPrefix != null) scarpetMatches.addAll(CarpetEventServer.Event.publicEvents().stream().
filter(s -> s.startsWith(eventPrefix)).map(s -> "__on_"+s+"(").collect(Collectors.toList()));
if (eventPrefix != null) scarpetMatches.addAll(CarpetEventServer.Event.publicEvents(null).stream().
filter(e -> e.name.startsWith(eventPrefix)).map(s -> "__on_"+s+"(").collect(Collectors.toList()));
scarpetMatches.addAll(host.globaFunctionNames(host.main, s -> s.startsWith(prefix)).map(s -> s+"(").collect(Collectors.toList()));
scarpetMatches.addAll(host.globaVariableNames(host.main, s -> s.startsWith(prefix)).collect(Collectors.toList()));
return scarpetMatches;
@@ -269,10 +269,10 @@ public class ScriptCommand
executes( (cc) -> listEvents(cc.getSource())).
then(literal("add_to").
then(argument("event", StringArgumentType.word()).
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.publicEvents() ,bb)).
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.publicEvents(CarpetServer.scriptServer).stream().map(ev -> ev.name).collect(Collectors.toList()),bb)).
then(argument("call", StringArgumentType.word()).
suggests( (cc, bb) -> suggestMatching(suggestFunctionCalls(cc), bb)).
executes( (cc) -> CarpetServer.scriptServer.events.addEvent(
executes( (cc) -> CarpetServer.scriptServer.events.addEventFromCommand(
cc.getSource(),
StringArgumentType.getString(cc, "event"),
null,
@@ -283,7 +283,7 @@ public class ScriptCommand
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.modules.keySet(), bb)).
then(argument("call", StringArgumentType.word()).
suggests( (cc, bb) -> suggestMatching(suggestFunctionCalls(cc), bb)).
executes( (cc) -> CarpetServer.scriptServer.events.addEvent(
executes( (cc) -> CarpetServer.scriptServer.events.addEventFromCommand(
cc.getSource(),
StringArgumentType.getString(cc, "event"),
StringArgumentType.getString(cc, "app"),
@@ -291,10 +291,10 @@ public class ScriptCommand
)?1:0)))))).
then(literal("remove_from").
then(argument("event", StringArgumentType.word()).
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.publicEvents() ,bb)).
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.publicEvents(CarpetServer.scriptServer).stream().map(ev -> ev.name).collect(Collectors.toList()) ,bb)).
then(argument("call", StringArgumentType.greedyString()).
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.byName.get(StringArgumentType.getString(cc, "event")).handler.callList.stream().map(CarpetEventServer.Callback::toString), bb)).
executes( (cc) -> CarpetServer.scriptServer.events.removeEvent(
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(
cc.getSource(),
StringArgumentType.getString(cc, "event"),
StringArgumentType.getString(cc, "call")
@@ -335,7 +335,7 @@ public class ScriptCommand
private static int listEvents(ServerCommandSource source)
{
Messenger.m(source, "w Lists ALL event handlers:");
for (CarpetEventServer.Event event: CarpetEventServer.Event.byName.values())
for (CarpetEventServer.Event event: CarpetEventServer.Event.getAllEvents(CarpetServer.scriptServer, null))
{
boolean shownEvent = false;
for (CarpetEventServer.Callback c: event.handler.callList)
@@ -45,6 +45,8 @@ public class EntityPlayerActionPack
private float forward;
private float strafing;
private int itemUseCooldown;
public EntityPlayerActionPack(ServerPlayerEntity playerIn)
{
player = playerIn;
@@ -62,6 +64,8 @@ public class EntityPlayerActionPack
sprinting = other.sprinting;
forward = other.forward;
strafing = other.strafing;
itemUseCooldown = other.itemUseCooldown;
}
public EntityPlayerActionPack start(ActionType type, Action action)
@@ -279,6 +283,16 @@ public class EntityPlayerActionPack
@Override
boolean execute(ServerPlayerEntity player, Action action)
{
EntityPlayerActionPack ap = ((ServerPlayerEntityInterface) player).getActionPack();
if (ap.itemUseCooldown > 0)
{
ap.itemUseCooldown--;
return true;
}
if (player.isUsingItem())
{
return true;
}
HitResult hit = getTarget(player);
for (Hand hand : Hand.values())
{
@@ -297,6 +311,7 @@ public class EntityPlayerActionPack
if (result.isAccepted())
{
if (result.shouldSwingHand()) player.swingHand(hand);
ap.itemUseCooldown = 3;
return true;
}
}
@@ -310,14 +325,26 @@ public class EntityPlayerActionPack
boolean handWasEmpty = player.getStackInHand(hand).isEmpty();
boolean itemFrameEmpty = (entity instanceof ItemFrameEntity) && ((ItemFrameEntity) entity).getHeldItemStack().isEmpty();
Vec3d relativeHitPos = entityHit.getPos().subtract(entity.getX(), entity.getY(), entity.getZ());
if (entity.interactAt(player, relativeHitPos, hand).isAccepted()) return true;
if (entity.interactAt(player, relativeHitPos, hand).isAccepted())
{
ap.itemUseCooldown = 3;
return true;
}
// fix for SS itemframe always returns CONSUME even if no action is performed
if (player.interact(entity, hand).isAccepted() && !(handWasEmpty && itemFrameEmpty)) return true;
if (player.interact(entity, hand).isAccepted() && !(handWasEmpty && itemFrameEmpty))
{
ap.itemUseCooldown = 3;
return true;
}
break;
}
}
ItemStack handItem = player.getStackInHand(hand);
if (player.interactionManager.interactItem(player, player.getServerWorld(), handItem, hand).isAccepted()) return true;
if (player.interactionManager.interactItem(player, player.getServerWorld(), handItem, hand).isAccepted())
{
ap.itemUseCooldown = 3;
return true;
}
}
return false;
}
@@ -325,6 +352,8 @@ public class EntityPlayerActionPack
@Override
void inactiveTick(ServerPlayerEntity player, Action action)
{
EntityPlayerActionPack ap = ((ServerPlayerEntityInterface) player).getActionPack();
ap.itemUseCooldown = 0;
player.stopUsingItem();
}
},
@@ -499,40 +528,52 @@ public class EntityPlayerActionPack
public final int offset;
private int count;
private int next;
private final boolean isContinuous;
private Action(int limit, int interval, int offset)
private Action(int limit, int interval, int offset, boolean continuous)
{
this.limit = limit;
this.interval = interval;
this.offset = offset;
next = interval + offset;
isContinuous = continuous;
}
public static Action once()
{
return new Action(1, 1, 0);
return new Action(1, 1, 0, false);
}
public static Action continuous()
{
return new Action(-1, 1, 0);
return new Action(-1, 1, 0, true);
}
public static Action interval(int interval)
{
return new Action(-1, interval, 0);
return new Action(-1, interval, 0, false);
}
public static Action interval(int interval, int offset)
{
return new Action(-1, interval, offset);
return new Action(-1, interval, offset, false);
}
Boolean tick(EntityPlayerActionPack actionPack, ActionType type)
{
next--;
Boolean cancel = null;
if (next <= 0) {
if (next <= 0)
{
if (interval == 1 && !isContinuous)
{
// need to allow entity to tick, otherwise won't have effect (bow)
// actions are 20 tps, so need to clear status mid tick, allowing entities process it till next time
if (!type.preventSpectator || !actionPack.player.isSpectator())
{
type.inactiveTick(actionPack.player, this);
}
}
if (!type.preventSpectator || !actionPack.player.isSpectator())
{
@@ -22,4 +22,23 @@ public class WorldChunk_fillUpdatesMixin
if (!CarpetSettings.impendingFillSkipUpdates)
blockState.onBlockAdded(world_1, blockPos_1, blockState_1, boolean_1);
}
@Redirect(method = "setBlockState", at = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/BlockState;onStateReplaced(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Z)V"
))
private void onRemovedBlock(BlockState blockState, World world, BlockPos pos, BlockState state, boolean moved)
{
if (CarpetSettings.impendingFillSkipUpdates) // doing due dilligence from AbstractBlock onStateReplaced
{
if (blockState.getBlock().hasBlockEntity() && !blockState.isOf(state.getBlock()))
{
world.removeBlockEntity(pos);
}
}
else
{
blockState.onStateReplaced(world, pos, state, moved);
}
}
}
@@ -11,6 +11,7 @@ import carpet.script.value.NBTSerializableValue;
import carpet.script.value.NumericValue;
import carpet.script.value.StringValue;
import carpet.script.value.Value;
import carpet.script.value.ValueConversions;
import carpet.settings.ParsedRule;
import carpet.utils.Messenger;
import net.minecraft.block.BlockState;
@@ -48,6 +49,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -58,6 +60,7 @@ public class CarpetEventServer
public final List<ScheduledCall> scheduledCalls = new LinkedList<>();
public final MinecraftServer server;
private static final List<Value> NOARGS = Collections.emptyList();
public final Map<String, Event> customEvents = new HashMap<>();
public static class Callback
{
@@ -94,6 +97,23 @@ public class CarpetEventServer
}
}
/**
* Used also in entity events
* @param recipient - optional target player argument
* @param runtimeArgs = options
*/
public Boolean targetPlayer(ServerPlayerEntity recipient, List<Value> runtimeArgs)
{
List<Value> args = runtimeArgs;
if (!this.parametrizedArgs.isEmpty())
{
args = new ArrayList<>(runtimeArgs);
args.addAll(this.parametrizedArgs);
}
return CarpetServer.scriptServer.runForPlayer(recipient, host, function, args);
}
@Override
public String toString()
{
@@ -152,6 +172,23 @@ public class CarpetEventServer
for (Callback call : fails) callList.remove(call);
}
}
public int callCustom(ServerPlayerEntity receipient, List<Value> callArg)
{
if (callList.isEmpty()) return 0;
//List<Callback> fails = new ArrayList<>();
// skipping fails on purpose - its a player induced call.
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++;
}
//for (Callback call : fails) callList.remove(call);
return successes;
}
public boolean addEventCall(ServerCommandSource source, String hostName, String funName, Function<ScriptHost, Boolean> verifier)
{
ScriptHost host = CarpetServer.scriptServer.getHostByName(hostName);
@@ -198,9 +235,9 @@ public class CarpetEventServer
callList.removeIf((c)-> c.function.getString().equals(funName) && ( hostName == c.host || (c.host != null && c.host.equalsIgnoreCase(hostName) )) );
}
public void removeAllCalls(String hostName)
public void removeAllCalls(CarpetScriptHost host)
{
callList.removeIf((c)-> c.host != null && c.host.equals(hostName));
callList.removeIf((c)-> c.host != null && c.host.equals(host.getName()));
}
public void clearEverything()
{
@@ -211,9 +248,11 @@ public class CarpetEventServer
public static class Event
{
public static final Map<String, Event> byName = new HashMap<>();
public static List<String> publicEvents()
public static List<Event> publicEvents(CarpetScriptServer server)
{
return byName.entrySet().stream().filter(e -> e.getValue().isPublic).map(Map.Entry::getKey).collect(Collectors.toList());
List<Event> events = byName.values().stream().filter(e -> e.isPublic).collect(Collectors.toList());
if (server != null) events.addAll(server.events.customEvents.values());
return events;
}
public static final Event TICK = new Event("tick", 0, true)
@@ -674,15 +713,15 @@ public class CarpetEventServer
}
};
public static String getLoadEvent(EntityType<? extends Entity> et)
public static String getEntityLoadEventName(EntityType<? extends Entity> et)
{
return "entity_loaded_" + Registry.ENTITY_TYPE.getId(et);
return "entity_loaded_" + ValueConversions.of(Registry.ENTITY_TYPE.getId(et)).getString();
}
public static final Map<EntityType<? extends Entity>, Event> ENTITY_LOAD= new HashMap<EntityType<? extends Entity>, Event>() {{
EntityType.get("zombie");
Registry.ENTITY_TYPE.forEach(et -> {
put(et, new Event(getLoadEvent(et), 1, true, false)
put(et, new Event(getEntityLoadEventName(et), 1, true, false)
{
@Override
public void onEntityAction(Entity entity)
@@ -715,6 +754,52 @@ public class CarpetEventServer
this.isPublic = isPublic;
byName.put(name, this);
}
public static List<Event> getAllEvents(CarpetScriptServer server, Predicate<Event> predicate)
{
List<CarpetEventServer.Event> eventList = new ArrayList<>(CarpetEventServer.Event.byName.values());
eventList.addAll(server.events.customEvents.values());
if (predicate == null) return eventList;
return eventList.stream().filter(predicate).collect(Collectors.toList());
}
public static Event getEvent(String name, CarpetScriptServer server)
{
if (byName.containsKey(name)) return byName.get(name);
return server.events.customEvents.get(name);
}
public static Event getOrCreateCustom(String name, CarpetScriptServer server)
{
Event event = getEvent(name, server);
if (event != null) return event;
return new Event(name, server);
}
public static void removeAllHostEvents(CarpetScriptHost host)
{
byName.values().forEach((e) -> e.handler.removeAllCalls(host));
host.getScriptServer().events.customEvents.values().forEach((e) -> e.handler.removeAllCalls(host));
}
public static void clearAllBuiltinEvents()
{
byName.values().forEach(e -> e.handler.clearEverything());
}
// custom event constructor
private Event(String name, CarpetScriptServer server)
{
this.name = name;
this.handler = new CallbackList(1);
this.globalOnly = false;
this.isPublic = true;
server.events.customEvents.put(name, this);
}
//handle_event('event', function...)
//signal_event('event', player or null, args.... ) -> number of apps notified
public boolean isNeeded()
{
return handler.callList.size() > 0;
@@ -748,8 +833,7 @@ public class CarpetEventServer
public CarpetEventServer(MinecraftServer server)
{
this.server = server;
for (Event e: Event.byName.values())
e.handler.callList.clear();
Event.clearAllBuiltinEvents();
}
public void tick()
@@ -777,20 +861,21 @@ public class CarpetEventServer
scheduledCalls.add(new ScheduledCall(context, function, args, due));
}
public boolean addEvent(ServerCommandSource source, String event, String host, String funName)
public boolean addEventFromCommand(ServerCommandSource source, String event, String host, String funName)
{
if (!Event.byName.containsKey(event))
Event ev = Event.getEvent(event, CarpetServer.scriptServer);
if (ev == null)
{
return false;
}
Event ev = Event.byName.get(event);
boolean added = ev.handler.addEventCall(source, host, funName, h -> canAddEvent(ev, h));
if (added) Messenger.m(source, "gi Added " + funName + " to " + event);
return added;
}
public void addEventDirectly(String event, ScriptHost host, FunctionValue function, List<Value> args)
public void addBuiltInEvent(String event, ScriptHost host, FunctionValue function, List<Value> args)
{
// 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");
@@ -798,51 +883,61 @@ public class CarpetEventServer
if (!success) throw new InternalExpressionException("Global event "+event+" requires "+ev.handler.reqArgs+", not "+(function.getNumParams()-((args==null)?0:args.size())));
}
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");
return ev.handler.addEventCallInternal(host, function, args==null?NOARGS:args);
}
public int signalEvent(String event, CarpetScriptHost host, ServerPlayerEntity player, List<Value> callArgs)
{
Event ev = Event.getEvent(event, host.getScriptServer());
if (ev == null) return -1;
return ev.handler.callCustom(player, callArgs);
}
private boolean canAddEvent(Event event, ScriptHost host)
{
return !(event.globalOnly && (host.perUser || host.parent != null));
}
public boolean removeEvent(ServerCommandSource source, String event, String funName)
public boolean removeEventFromCommand(ServerCommandSource source, String event, String funName)
{
if (!Event.byName.containsKey(event))
Event ev = Event.getEvent(event, CarpetServer.scriptServer);
if (ev == null)
{
Messenger.m(source, "r Unknown event: " + event);
return false;
}
Pair<String,String> call = decodeCallback(funName);
Event.byName.get(event).handler.removeEventCall(call.getLeft(), call.getRight());
ev.handler.removeEventCall(call.getLeft(), call.getRight());
// could verified if actually removed
Messenger.m(source, "gi Removed event: " + funName + " from "+event);
return true;
}
public boolean removeEventDirectly(String event, ScriptHost host)
public boolean removeBuiltInEvent(String event, CarpetScriptHost host)
{
if (!Event.byName.containsKey(event))
{
return false;
}
Event.byName.get(event).handler.removeAllCalls(host.getName());
Event ev = Event.getEvent(event, host.getScriptServer());
if (ev == null) return false;
ev.handler.removeAllCalls(host);
return true;
}
public void removeEventDirectly(String event, ScriptHost host, String funName)
public void removeBuiltInEvent(String event, CarpetScriptHost host, String funName)
{
Event.byName.get(event).handler.removeEventCall(host.getName(), funName);
Event ev = Event.getEvent(event, host.getScriptServer());
if (ev != null) ev.handler.removeEventCall(host.getName(), funName);
}
public void removeAllHostEvents(String hostName)
public void removeAllHostEvents(CarpetScriptHost host)
{
Event.byName.values().forEach((e) -> e.handler.removeAllCalls(hostName));
scheduledCalls.removeIf(sc -> sc.host != null && sc.host.equals(hostName));
}
public void clearAll()
{
Event.byName.values().forEach(e -> e.handler.clearEverything());
// remove event handlers
Event.removeAllHostEvents(host);
// remove scheduled calls
scheduledCalls.removeIf(sc -> sc.host != null && sc.host.equals(host.getName()));
}
private Pair<String,String> decodeCallback(String funName)
@@ -117,7 +117,7 @@ public class CarpetScriptHost extends ScriptHost
// this is nasty, we have the host and function, yet we add it via names, but hey - works for now
String event = funName.replaceFirst("__on_", "");
if (CarpetEventServer.Event.byName.containsKey(event))
scriptServer.events.addEventDirectly(event, this, function, null);
scriptServer.events.addBuiltInEvent(event, this, function, null);
}
else if (funName.equals("__config"))
{
@@ -188,8 +188,7 @@ public class CarpetScriptHost extends ScriptHost
{
// this is nasty, we have the host and function, yet we add it via names, but hey - works for now
String event = funName.replaceFirst("__on_","");
if (CarpetEventServer.Event.byName.containsKey(event))
scriptServer.events.removeEventDirectly(event, this, funName);
scriptServer.events.removeBuiltInEvent(event, this, funName);
}
}
@@ -212,6 +211,22 @@ public class CarpetScriptHost extends ScriptHost
return host;
}
public CarpetScriptHost retrieveForExecution(ServerPlayerEntity target)
{
// allowing only run
if (perUser == (target == null)) return null;
if (!perUser)
{
if (errorSnooper == null) setChatErrorSnooper(this.scriptServer.server.getCommandSource());
return this;
}
// user based
CarpetScriptHost userHost = (CarpetScriptHost)retrieveForExecution(target.getName().getString());
if (userHost.errorSnooper == null) userHost.setChatErrorSnooper(target.getCommandSource());
return userHost;
}
public Value handleCommandLegacy(ServerCommandSource source, String call, List<Integer> coords, String arg)
{
try
@@ -20,6 +20,7 @@ import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.tree.CommandNode;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText;
import net.minecraft.util.WorldSavePath;
import net.minecraft.util.math.BlockPos;
@@ -372,7 +373,7 @@ public class CarpetScriptServer
return false;
}
// stop all events associated with name
events.removeAllHostEvents(name);
events.removeAllHostEvents(modules.get(name));
modules.get(name).onClose();
modules.remove(name);
if (!isRuleApp) unloadableModules.remove(name);
@@ -402,6 +403,35 @@ public class CarpetScriptServer
return true;
}
public Boolean runForPlayer(ServerPlayerEntity recipient, String hostname, FunctionValue udf, List<Value> argv)
{
CarpetScriptHost host;
ServerCommandSource source;
if (hostname == null)
{
if (recipient != null) return null;
host = globalHost;
source = server.getCommandSource();
}
else
{
host = modules.get(hostname).retrieveForExecution(recipient);
if (host == null) // not applicable
return null;
source = (recipient == null)? server.getCommandSource() : recipient.getCommandSource();
}
try
{
host.callUDF(BlockPos.ORIGIN, source.withLevel(CarpetSettings.runPermissionLevel), udf, argv);
}
catch (NullPointerException | InvalidCallbackException npe)
{
return false;
}
return true;
}
public void tick()
{
events.tick();
@@ -424,7 +454,7 @@ public class CarpetScriptServer
Map<String, Boolean> apps = new HashMap<>();
modules.forEach((s, h) -> apps.put(s, h.perUser));
apps.keySet().forEach(s -> removeScriptHost(server.getCommandSource(), s, false, false));
events.clearAll();
CarpetEventServer.Event.clearAllBuiltinEvents();
init();
apps.forEach((s, pp) -> addScriptHost(server.getCommandSource(), s, pp, false, false));
}
+49 -2
View File
@@ -7,7 +7,9 @@ import carpet.fakes.StatTypeInterface;
import carpet.fakes.ThreadedAnvilChunkStorageInterface;
import carpet.helpers.FeatureGenerator;
import carpet.script.CarpetContext;
import carpet.script.CarpetEventServer;
import carpet.script.CarpetScriptHost;
import carpet.script.CarpetScriptServer;
import carpet.script.Context;
import carpet.script.Expression;
import carpet.script.LazyValue;
@@ -20,6 +22,7 @@ import carpet.script.utils.ShapeDispatcher;
import carpet.script.utils.WorldTools;
import carpet.script.value.EntityValue;
import carpet.script.value.FormattedTextValue;
import carpet.script.value.FunctionValue;
import carpet.script.value.ListValue;
import carpet.script.value.NBTSerializableValue;
import carpet.script.value.NullValue;
@@ -639,12 +642,12 @@ public class Auxiliary {
throw new InternalExpressionException("'schedule' should have at least 2 arguments, delay and call name");
long delay = NumericValue.asNumber(lv.get(0).evalValue(c)).getLong();
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, true, false, true);
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, true);
CarpetServer.scriptServer.events.scheduleCall(
(CarpetContext) c,
functionArgument.function,
functionArgument.resolveArgs(c, Context.NONE),
functionArgument.resolveArgs(c, t),
delay
);
return (c_, t_) -> Value.TRUE;
@@ -843,6 +846,50 @@ public class Auxiliary {
return LazyValue.NULL;
return (_c, _t) -> new NumericValue(player.getStatHandler().getStat(stat));
});
//handle_event('event', function...)
expression.addLazyFunction("handle_event", -1, (c, t, lv) ->
{
if (lv.size() < 2)
throw new InternalExpressionException("'handle_event' requires at least two arguments, event name, and a callback");
String event = lv.get(0).evalValue(c).getString();
FunctionArgument callback = FunctionArgument.findIn(c, expression.module, lv, 1, true, false);
CarpetScriptHost host = ((CarpetScriptHost)c.host);
Value success;
if (callback.function == null)
{
success = host.getScriptServer().events.removeBuiltInEvent(event, host)?Value.TRUE:Value.FALSE;
}
else
{
success = host.getScriptServer().events.handleCustomEvent(event, host, callback.function, FunctionValue.resolveArgs(callback.args, c, t) )?Value.TRUE:Value.FALSE;
}
return (cc, tt) -> success;
});
//signal_event('event', player or null, args.... ) -> number of apps notified
expression.addLazyFunction("signal_event", -1, (c, t, lv) ->
{
if (lv.size() == 0)
throw new InternalExpressionException("'signal' requires at least one argument");
CarpetScriptServer server = ((CarpetScriptHost)c.host).getScriptServer();
String eventName = lv.get(0).evalValue(c).getString();
// no such event yet
if (CarpetEventServer.Event.getEvent(eventName, server) == null) return LazyValue.NULL;
ServerPlayerEntity player = null;
List<Value> args = Collections.emptyList();
if (lv.size() > 1)
{
player = EntityValue.getPlayerByValue(server.server, lv.get(1).evalValue(c));
if (lv.size() > 2)
{
args = FunctionValue.resolveArgs(lv.subList(2, lv.size()), c, t);
}
}
int counts = ((CarpetScriptHost)c.host).getScriptServer().events.signalEvent(eventName, (CarpetScriptHost) c.host, player, args);
if (counts < 0) return LazyValue.NULL;
Value ret = new NumericValue(counts);
return (cc, tt) -> ret;
});
}
private static <T> Stat<T> getStat(StatType<T> type, Identifier id)
@@ -276,15 +276,15 @@ public class Entities {
: Collections.singletonList(entityValue.getString());
Set<EntityType<? extends Entity>> types = new HashSet<>();
descriptors.forEach(s -> types.addAll(EntityValue.getEntityDescriptor(s).typeList));
FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 1, false, true, false);
FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 1, true, false);
CarpetEventServer events = ((CarpetScriptHost)c.host).getScriptServer().events;
if (funArg.function == null)
{
types.forEach(et -> events.removeEventDirectly(CarpetEventServer.Event.getLoadEvent(et), c.host));
types.forEach(et -> events.removeBuiltInEvent(CarpetEventServer.Event.getEntityLoadEventName(et), (CarpetScriptHost) c.host));
}
else
{
types.forEach(et -> events.addEventDirectly(CarpetEventServer.Event.getLoadEvent(et), c.host, funArg.function, FunctionValue.resolveArgs(funArg.args, c, t)));
types.forEach(et -> events.addBuiltInEvent(CarpetEventServer.Event.getEntityLoadEventName(et), c.host, funArg.function, FunctionValue.resolveArgs(funArg.args, c, t)));
}
Value ret = new NumericValue(types.size());
return (cc, tt) -> ret;
@@ -300,7 +300,7 @@ public class Entities {
throw new InternalExpressionException("First argument to entity_event should be an entity");
String what = lv.get(1).evalValue(c).getString();
FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 2, false, true, false);
FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 2, true, false);
((EntityValue) v).setEvent((CarpetContext)c, what, funArg.function, FunctionValue.resolveArgs(funArg.args, c, t));
@@ -28,7 +28,6 @@ public class FunctionArgument extends Argument
* @param module module
* @param params list of lazy params
* @param offset offset where to start looking for functional argument
* @param prematureEvaluation evaluates eagerly arguments in current context before returning
* @param allowNone none indicates no function present, otherwise it will croak
* @param checkArgs whether the caller expects trailing parameters to fully resolve function argument list
* if not - argument count check will not be performed and its up to the caller to verify
@@ -40,7 +39,6 @@ public class FunctionArgument extends Argument
Module module,
List<LazyValue> params,
int offset,
boolean prematureEvaluation,
boolean allowNone,
boolean checkArgs)
{
@@ -66,18 +64,7 @@ public class FunctionArgument extends Argument
throw new InternalExpressionException("Function " + fun.getPrettyString() + " requires " + fun.getArguments().size() + " arguments");
}
List<LazyValue> lvargs = new ArrayList<>();
if (prematureEvaluation)
{
for (int i = offset+1, mx = params.size(); i < mx; i++)
{
Value arg = params.get(i).evalValue(c);
lvargs.add((cc, tt) -> arg);
}
}
else
{
for (int i = offset+1, mx = params.size(); i < mx; i++) lvargs.add(params.get(i));
}
for (int i = offset+1, mx = params.size(); i < mx; i++) lvargs.add(params.get(i));
return new FunctionArgument(fun, offset+1+argsize, lvargs);
}
@@ -43,7 +43,7 @@ public class Functions {
//lv.remove(lv.size()-1); // aint gonna cut it // maybe it will because of the eager eval changes
if (t != Context.SIGNATURE) // just call the function
{
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, false, true);
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, true);
FunctionValue fun = functionArgument.function;
Value retval = fun.callInContext(expr, c, t, fun.getExpression(), fun.getToken(), functionArgument.args).evalValue(c);
return (cc, tt) -> retval; ///!!!! dono might need to store expr and token in statics? (e? t?)
@@ -4,6 +4,7 @@ import carpet.script.Expression;
import carpet.script.argument.FunctionArgument;
import carpet.script.exception.ExitStatement;
import carpet.script.exception.InternalExpressionException;
import carpet.script.value.FunctionValue;
import carpet.script.value.NumericValue;
import carpet.script.value.ThreadValue;
import carpet.script.value.Value;
@@ -16,8 +17,8 @@ public class Threading
{
if (lv.size() == 0)
throw new InternalExpressionException("'task' requires at least function to call as a parameter");
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, true, false, true);
ThreadValue thread = new ThreadValue(Value.NULL, functionArgument.function, expr, tok, c, functionArgument.args);
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, true);
ThreadValue thread = new ThreadValue(Value.NULL, functionArgument.function, expr, tok, c, FunctionValue.resolveArgs(functionArgument.args, c, t));
Thread.yield();
return (cc, tt) -> thread;
});
@@ -27,8 +28,8 @@ public class Threading
if (lv.size() < 2)
throw new InternalExpressionException("'task' requires at least function to call as a parameter");
Value queue = lv.get(0).evalValue(c);
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, true, false, true);
ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, functionArgument.args);
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, true);
ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, FunctionValue.resolveArgs(functionArgument.args, c, t));
Thread.yield();
return (cc, tt) -> thread;
});
@@ -131,6 +131,10 @@ public class EntityValue extends Value
player = (ServerPlayerEntity) e;
}
}
else if (value.isNull())
{
return null;
}
else
{
String playerName = value.getString();
@@ -20,7 +20,7 @@ public class ThreadValue extends Value
private final long id;
private static long sequence = 0L;
public ThreadValue(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<LazyValue> args)
public ThreadValue(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<Value> args)
{
id = sequence++;
ExecutorService executor = ctx.host.getExecutor(pool);
@@ -36,7 +36,7 @@ public class ThreadValue extends Value
{
try
{
return function.lazyEval(ctx, Context.NONE, expr, token, args).evalValue(ctx);
return function.lazyEval(ctx, Context.NONE, expr, token, FunctionValue.lazify(args)).evalValue(ctx);
}
catch (ExitStatement exit)
{