entity load handler and rework of handling of events.

This commit is contained in:
gnembon committed 2020-10-30 22:59:27 -03:00
1 parent 51f34643db
commit 7ccd46433a
15 files changed
+409 -295

No files matched your search

+47 -13
View File
@@ -24,20 +24,33 @@ run, or by UUID, obtained via `entity ~ 'uuid'`. It returns null if no such enti
entities between calls, as missing entities will be returning `null`. Both calls using UUID or numerical ID are `O(1)`,
but obviously using UUIDs takes more memory and compute.
### `entity_list(type)`
### `entity_list(descriptor)`
Returns global lists of entities in the current dimension of a specified type. Currently the following
selectors are available:
Returns global lists of entities in the current dimension matches specified descriptor.
Calls to `entity_list` always fetch entities from the current world that the script executes.
* `*`: all entities, even `!valid`
### `entity_types(descriptor)`
Resolves a given descriptor returning list of entity types that match it. The returned list of types is also a valid list
of descriptors that can be use elsewhere where entity types are required.
Currently, the following descriptors are available:
* `*`: all entities, even `!valid`, matches all entity types.
* `valid` - all entities that are not dead (health > 0). All main categories below also return only
entities in the `valid` category.
* `living` - all entities that resemble a creature of any sort
* `projectile` - all entities that are not living that can be throw or projected
* `undead`, `arthropod`, `aquatic`, `regular`, `illager` - all entities that belong to any of these groups. Every
living entity belongs to one and only one of these.
entities in the `valid` category. matches all entity types. `!valid` matches all entites that are already dead of all types.
* `living` - all entities that resemble a creature of some sort
* `projectile` - all entities or types that are not living that can be throw or projected, `!projectile` matches all types that
are not living, but cannot the thrown or projected.
* `minecarts` matches all minecart types. `!minecart` matches all types that are not live, but also not minecarts.
* `undead`, `arthropod`, `aquatic`, `regular`, `illager` - all entities / types that belong to any of these groups. All
living entities belong to one and only one of these. Corresponding negative (e.g. `!undead`) corresponds to all mobs that are
living but don't belong to that group. Entity groups are used in interaction / battle mechanics like smite for undead, or impaling
for aquatic. Also certain mobs interact with groups, like bell with illagers. ALl mobs that don't have any of these traits belong
to the `regular` group.
* `monster`, `creature`, `ambient`, `water_creature`, `water_ambient`, `misc` - another categorization of
living entities based on their spawn group.
living entities based on their spawn group. Negative descriptor resolves to all living types that don't belong to that
category.
* Any of the following standard entity types (equivalent to selection from `/summon` vanilla command:
`area_effect_cloud`, `armor_stand`, `arrow`, `bat`, `bee`, `blaze`, `boat`, `cat`, `cave_spider`, `chest_minecart`,
`chicken`, `cod`, `command_block_minecart`, `cow`, `creeper`, `dolphin`, `donkey`, `dragon_fireball`, `drowned`,
@@ -53,8 +66,8 @@ living entities based on their spawn group.
`wither`, `wither_skeleton`, `wither_skull`, `wolf`, `zoglin`, `zombie`, `zombie_horse`, `zombie_villager`,
`zombified_piglin`
All categories can be preceded with `'!'` which will fetch all entities that are valid (health > 0) but not
belonging to that group. Calls to `entity_list` always fetch entities from the current world that the script executes.
All categories can be preceded with `'!'` which will fetch all entities (unless otherwise noted) that are valid (health > 0) but not
belonging to that group.
### `entity_area(type, center, distance)`
@@ -727,7 +740,28 @@ Required arguments: `entity, amount, source, attacking_entity`
It doesn't mean that all entity types will have a chance to execute a given event, but entities will not error
when you attach an inapplicable event to it.
### `entity_event(e, event, call_name, args...)`
### `entity_load_handler(descriptor / descriptors, function)`, `entity_load_handler(descriptor / descriptors, call_name, ... args?)`
Attaches a callback to when any entity matching the following type / types is loaded in the game, allowing to grab a handle
to an entity right when it is loaded to the world without querying them every tick. Callback expects one parameter - the entity.
If callback is `null` current entity handler, if present is removed. Consecutive calls to `entity_load_handler` will add / subtract
of the currenty targetted entity types pool.
Like other global events, calls to `entity_load_handler` can only be attached in apps with global scope. Player scope make so
that it is not clear which player to use run the load call.
```
// veryfast method of getting rid of all the zombies. Callback is so early, its packets haven't reached yet the clients
// so to save on log errors, removal of mobs needs to be scheduled for later.
entity_load_handler('zombie', _(e) -> schedule(0, _(outer(e)) -> modify(e, 'remove')))
// making all zombies immediately faster and less susceptible to friction of any sort
entity_load_handler('zombie', _(e) -> entity_event(e, 'on_tick', _(e) -> modify(e, 'motion', 1.2*e~'motion')))
```
### `entity_event(e, event, function)`, `entity_event(e, event, call_name, ... args?)`
Attaches specific function from the current package to be called upon the `event`, with extra `args` carried to the
original required arguments for the event handler.
@@ -26,7 +26,9 @@ entity_area
entity_event
entity_id
entity_list
entity_load_handler
entity_selector
entity_types
escape_nbt
flammable
format
@@ -60,7 +60,7 @@
scoreboard scoreboard_add scoreboard_remove scoreboard_display
player spawn entity_id entity_list entity_area entity_selector query modify entity_event
player spawn entity_id entity_list entity_area entity_selector query modify entity_event entity_load_handler entity_types
stack_limit item_category recipe_data crafting_remaining_item
@@ -74,7 +74,7 @@ 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.byName.keySet().stream().
if (eventPrefix != null) scarpetMatches.addAll(CarpetEventServer.Event.publicEvents().stream().
filter(s -> s.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()));
@@ -269,7 +269,7 @@ public class ScriptCommand
executes( (cc) -> listEvents(cc.getSource())).
then(literal("add_to").
then(argument("event", StringArgumentType.word()).
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.byName.keySet() ,bb)).
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.publicEvents() ,bb)).
then(argument("call", StringArgumentType.word()).
suggests( (cc, bb) -> suggestMatching(suggestFunctionCalls(cc), bb)).
executes( (cc) -> CarpetServer.scriptServer.events.addEvent(
@@ -291,7 +291,7 @@ public class ScriptCommand
)?1:0)))))).
then(literal("remove_from").
then(argument("event", StringArgumentType.word()).
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.byName.keySet() ,bb)).
suggests( (cc, bb) -> suggestMatching(CarpetEventServer.Event.publicEvents() ,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(
+144 -128
View File
@@ -34,7 +34,6 @@ import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.dimension.DimensionType;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
@@ -62,11 +61,36 @@ public class CarpetEventServer
{
public final String host;
public final FunctionValue function;
public final List<Value> parametrizedArgs;
public Callback(String host, FunctionValue function)
public Callback(String host, FunctionValue function, List<Value> parametrizedArgs)
{
this.host = host;
this.function = function;
this.parametrizedArgs = parametrizedArgs;
}
/**
* Used in entity events
* @param asSource - entity command source
* @param runtimeArgs = options
*/
public boolean execute(ServerCommandSource asSource, List<Value> runtimeArgs)
{
//!CarpetServer.scriptServer.runas(source, call.host, call.function, argv)
//CarpetServer.scriptServer.runas(source, call.host, call.function, argv)
if (this.parametrizedArgs == null || this.parametrizedArgs.isEmpty())
return CarpetServer.scriptServer.runas(
asSource.withLevel(CarpetSettings.runPermissionLevel),
host, function, runtimeArgs);
else
{
List<Value> combinedArgs = new ArrayList<>(runtimeArgs);
combinedArgs.addAll(this.parametrizedArgs);
return CarpetServer.scriptServer.runas(
asSource.withLevel(CarpetSettings.runPermissionLevel),
host, function, combinedArgs);
}
}
@Override
@@ -78,14 +102,13 @@ public class CarpetEventServer
public static class ScheduledCall extends Callback
{
public final List<Value> args;
private final CarpetContext ctx;
public long dueTime;
public ScheduledCall(CarpetContext context, FunctionValue function, List<Value> args, long dueTime)
{
super(context.host.getName(), function);
this.args = args;
super(context.host.getName(), function, args);
this.ctx = context;
this.dueTime = dueTime;
}
@@ -95,34 +118,10 @@ public class CarpetEventServer
*/
public void execute()
{
CarpetServer.scriptServer.runas(ctx.origin, ctx.s, host, function, lazify(args));
CarpetServer.scriptServer.runas(ctx.origin, ctx.s, host, function, parametrizedArgs);
}
/**
* Used in entity events
* @param asSource - entity command source
* @param args = options
*/
public void execute(ServerCommandSource asSource, List<Value> args)
{
if (this.args == null || this.args.isEmpty())
CarpetServer.scriptServer.runas(
ctx.origin, asSource.withLevel(CarpetSettings.runPermissionLevel),
host, function, lazify(args));
else
{
List<Value> combinedArgs = new ArrayList<>();
combinedArgs.addAll(args);
combinedArgs.addAll(this.args);
CarpetServer.scriptServer.runas(
ctx.origin, asSource.withLevel(CarpetSettings.runPermissionLevel),
host, function, lazify(combinedArgs));
}
}
private List<LazyValue> lazify(List<Value> args)
{
return args.stream().map(v -> (LazyValue) (c, t) -> v ).collect(Collectors.toList());
}
}
public static class CallbackList
@@ -137,18 +136,17 @@ public class CarpetEventServer
this.reqArgs = reqArgs;
}
public void call(Supplier<List<LazyValue>> argumentSupplier, Supplier<ServerCommandSource> cmdSourceSupplier)
public void call(Supplier<List<Value>> argumentSupplier, Supplier<ServerCommandSource> cmdSourceSupplier)
{
if (callList.size() > 0)
{
List<LazyValue> argv = argumentSupplier.get(); // empty for onTickDone
List<Value> argv = argumentSupplier.get(); // empty for onTickDone
ServerCommandSource source = cmdSourceSupplier.get();
assert argv.size() == reqArgs;
List<Callback> fails = new ArrayList<>();
for (Callback call: callList)
{
if (!CarpetServer.scriptServer.runas(source, call.host, call.function, argv))
fails.add(call);
if (!call.execute(source, argv)) fails.add(call);
}
for (Callback call : fails) callList.remove(call);
}
@@ -178,19 +176,19 @@ public class CarpetEventServer
//remove duplicates
removeEventCall(hostName, udf.getString());
callList.add(new Callback(hostName, udf));
callList.add(new Callback(hostName, udf, null));
return true;
}
public boolean addEventCallDirect(ScriptHost host, FunctionValue function)
public boolean addEventCallInternal(ScriptHost host, FunctionValue function, List<Value> args)
{
if (function == null || function.getArguments().size() != reqArgs)
if (function == null || (function.getArguments().size() - (args==null?0:args.size())) != reqArgs)
{
return false;
}
//all clear
//remove duplicates
removeEventCall(host.getName(), function.getString());
callList.add(new Callback(host.getName(), function));
callList.add(new Callback(host.getName(), function, args));
return true;
}
@@ -259,8 +257,8 @@ public class CarpetEventServer
{
ChunkPos pos = chunk.getPos();
return Arrays.asList(
((c, t) -> new NumericValue(pos.x << 4)),
((c, t) -> new NumericValue(pos.z << 4))
(new NumericValue(pos.x << 4)),
(new NumericValue(pos.z << 4))
);
}, () -> CarpetServer.minecraft_server.getCommandSource().withWorld(world)
);
@@ -272,7 +270,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_DEPLOYS_ELYTRA = new Event("player_deploys_elytra", 1, false)
@@ -280,7 +278,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_WAKES_UP = new Event("player_wakes_up", 1, false)
@@ -288,7 +286,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_RIDES = new Event("player_rides", 5, false)
@@ -297,11 +295,11 @@ public class CarpetEventServer
public void onMountControls(ServerPlayerEntity player, float strafeSpeed, float forwardSpeed, boolean jumping, boolean sneaking)
{
handler.call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new NumericValue(forwardSpeed)),
((c, t) -> new NumericValue(strafeSpeed)),
((c, t) -> new NumericValue(jumping)),
((c, t) -> new NumericValue(sneaking))
(new EntityValue(player)),
(new NumericValue(forwardSpeed)),
(new NumericValue(strafeSpeed)),
(new NumericValue(jumping)),
(new NumericValue(sneaking))
), player::getCommandSource);
}
};
@@ -314,9 +312,9 @@ public class CarpetEventServer
{
//ItemStack itemstack = player.getStackInHand(enumhand);
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> ListValue.fromItemStack(itemstack)),
((c, t) -> new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand"))
(new EntityValue(player)),
(ListValue.fromItemStack(itemstack)),
(new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand"))
);
}, player::getCommandSource);
}
@@ -329,9 +327,9 @@ public class CarpetEventServer
handler.call( () ->
{
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new BlockValue(null, player.getServerWorld(), blockpos)),
((c, t) -> new StringValue(facing.getName()))
(new EntityValue(player)),
(new BlockValue(null, player.getServerWorld(), blockpos)),
(new StringValue(facing.getName()))
);
}, player::getCommandSource);
}
@@ -348,12 +346,12 @@ public class CarpetEventServer
Direction enumfacing = hitRes.getSide();
Vec3d vec3d = hitRes.getPos().subtract(blockpos.getX(), blockpos.getY(), blockpos.getZ());
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> ListValue.fromItemStack(itemstack)),
((c, t) -> new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")),
((c, t) -> new BlockValue(null, player.getServerWorld(), blockpos)),
((c, t) -> new StringValue(enumfacing.getName())),
((c, t) -> ListValue.of(
(new EntityValue(player)),
(ListValue.fromItemStack(itemstack)),
(new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")),
(new BlockValue(null, player.getServerWorld(), blockpos)),
(new StringValue(enumfacing.getName())),
(ListValue.of(
new NumericValue(vec3d.x),
new NumericValue(vec3d.y),
new NumericValue(vec3d.z)
@@ -373,11 +371,11 @@ public class CarpetEventServer
Direction enumfacing = hitRes.getSide();
Vec3d vec3d = hitRes.getPos().subtract(blockpos.getX(), blockpos.getY(), blockpos.getZ());
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")),
((c, t) -> new BlockValue(null, player.getServerWorld(), blockpos)),
((c, t) -> new StringValue(enumfacing.getName())),
((c, t) -> ListValue.of(
(new EntityValue(player)),
(new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")),
(new BlockValue(null, player.getServerWorld(), blockpos)),
(new StringValue(enumfacing.getName())),
(ListValue.of(
new NumericValue(vec3d.x),
new NumericValue(vec3d.y),
new NumericValue(vec3d.z)
@@ -392,10 +390,10 @@ public class CarpetEventServer
public void onBlockPlaced(ServerPlayerEntity player, BlockPos pos, Hand enumhand, ItemStack itemstack)
{
handler.call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> ListValue.fromItemStack(itemstack)),
((c, t) -> new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")),
((c, t) -> new BlockValue(null, player.getServerWorld(), pos))
(new EntityValue(player)),
(ListValue.fromItemStack(itemstack)),
(new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")),
(new BlockValue(null, player.getServerWorld(), pos))
), player::getCommandSource);
}
};
@@ -405,8 +403,8 @@ public class CarpetEventServer
public void onBlockBroken(ServerPlayerEntity player, BlockPos pos, BlockState previousBS)
{
handler.call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new BlockValue(previousBS, player.getServerWorld(), pos))
(new EntityValue(player)),
(new BlockValue(previousBS, player.getServerWorld(), pos))
), player::getCommandSource);
}
};
@@ -416,9 +414,9 @@ public class CarpetEventServer
public void onEntityHandAction(ServerPlayerEntity player, Entity entity, Hand enumhand)
{
handler.call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new EntityValue(entity)),
((c, t) -> new StringValue(enumhand==Hand.MAIN_HAND?"mainhand":"offhand"))
(new EntityValue(player)),
(new EntityValue(entity)),
(new StringValue(enumhand==Hand.MAIN_HAND?"mainhand":"offhand"))
), player::getCommandSource);
}
};
@@ -430,8 +428,8 @@ public class CarpetEventServer
{
//ItemStack itemstack = player.getStackInHand(enumhand);
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> ListValue.fromItemStack(itemstack))
(new EntityValue(player)),
(ListValue.fromItemStack(itemstack))
);
}, player::getCommandSource);
}
@@ -443,8 +441,8 @@ public class CarpetEventServer
public void onEntityHandAction(ServerPlayerEntity player, Entity entity, Hand enumhand)
{
handler.call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new EntityValue(entity))
(new EntityValue(player)),
(new EntityValue(entity))
), player::getCommandSource);
}
};
@@ -453,7 +451,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_STOPS_SNEAKING = new Event("player_stops_sneaking", 1, false)
@@ -461,7 +459,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_STARTS_SPRINTING = new Event("player_starts_sprinting", 1, false)
@@ -469,7 +467,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_STOPS_SPRINTING = new Event("player_stops_sprinting", 1, false)
@@ -477,7 +475,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
@@ -490,9 +488,9 @@ public class CarpetEventServer
handler.call( () ->
{
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> ListValue.fromItemStack(itemstack)),
((c, t) -> new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand"))
(new EntityValue(player)),
(ListValue.fromItemStack(itemstack)),
(new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand"))
);
}, player::getCommandSource);
}
@@ -506,9 +504,9 @@ public class CarpetEventServer
handler.call( () ->
{
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> ListValue.fromItemStack(itemstack)),
((c, t) -> new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand"))
(new EntityValue(player)),
(ListValue.fromItemStack(itemstack)),
(new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand"))
);
}, player::getCommandSource);
}
@@ -518,7 +516,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_DROPS_STACK = new Event("player_drops_stack", 1, false)
@@ -526,7 +524,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_CHOOSES_RECIPE = new Event("player_chooses_recipe", 3, false)
@@ -537,9 +535,9 @@ public class CarpetEventServer
handler.call( () ->
{
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new StringValue(NBTSerializableValue.nameFromRegistryId(recipe))),
((c, t) -> new NumericValue(fullStack))
(new EntityValue(player)),
(new StringValue(NBTSerializableValue.nameFromRegistryId(recipe))),
(new NumericValue(fullStack))
);
}, player::getCommandSource);
}
@@ -553,9 +551,9 @@ public class CarpetEventServer
handler.call( () ->
{
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new NumericValue(from)),
((c, t) -> new NumericValue(to))
(new EntityValue(player)),
(new NumericValue(from)),
(new NumericValue(to))
);
}, player::getCommandSource);
}
@@ -565,7 +563,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_TAKES_DAMAGE = new Event("player_takes_damage", 4, false)
@@ -576,10 +574,10 @@ public class CarpetEventServer
handler.call( () ->
{
return Arrays.asList(
((c, t) -> new EntityValue(target)),
((c, t) -> new NumericValue(amount)),
((c, t) ->new StringValue(source.getName())),
((c, t) -> source.getAttacker()==null?Value.NULL:new EntityValue(source.getAttacker()))
( new EntityValue(target)),
( new NumericValue(amount)),
(new StringValue(source.getName())),
( source.getAttacker()==null?Value.NULL:new EntityValue(source.getAttacker()))
);
}, target::getCommandSource);
}
@@ -592,9 +590,9 @@ public class CarpetEventServer
handler.call( () ->
{
return Arrays.asList(
((c, t) -> new EntityValue(source.getAttacker())),
((c, t) -> new NumericValue(amount)),
((c, t) -> new EntityValue(target))
(new EntityValue(source.getAttacker())),
(new NumericValue(amount)),
(new EntityValue(target))
);
}, () -> source.getAttacker().getCommandSource());
}
@@ -604,8 +602,8 @@ public class CarpetEventServer
@Override
public void onEntityHandAction(ServerPlayerEntity player, Entity entity, Hand enumhand) {
handler.call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new EntityValue(entity))
(new EntityValue(player)),
(new EntityValue(entity))
), player::getCommandSource);
}
};
@@ -615,7 +613,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_RESPAWNS = new Event("player_respawns", 1, false)
@@ -623,7 +621,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_CHANGES_DIMENSION = new Event("player_changes_dimension", 5, false)
@@ -638,11 +636,11 @@ public class CarpetEventServer
Value toDimStr = new StringValue(NBTSerializableValue.nameFromRegistryId(dimTo.getValue()));
handler.call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> fromValue),
((c, t) -> fromDimStr),
((c, t) -> toValue),
((c, t) -> toDimStr)
(new EntityValue(player)),
(fromValue),
(fromDimStr),
(toValue),
(toDimStr)
), player::getCommandSource);
}
};
@@ -650,7 +648,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
handler.call( () -> Collections.singletonList((new EntityValue(player))), player::getCommandSource);
}
};
public static final Event PLAYER_DISCONNECTS = new Event("player_disconnects", 2, false) {
@@ -658,8 +656,8 @@ public class CarpetEventServer
public void onPlayerMessage(ServerPlayerEntity player, String message)
{
handler.call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new StringValue(message))
(new EntityValue(player)),
(new StringValue(message))
), player::getCommandSource);
}
};
@@ -680,10 +678,10 @@ public class CarpetEventServer
Identifier id = getStatId(stat);
if (skippedStats.contains(id)) return;
handler.call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.STAT_TYPE.getId(stat.getType())))),
((c, t) -> new StringValue(NBTSerializableValue.nameFromRegistryId(id))),
((c, t) -> new NumericValue(amount))
(new EntityValue(player)),
(new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.STAT_TYPE.getId(stat.getType())))),
(new StringValue(NBTSerializableValue.nameFromRegistryId(id))),
(new NumericValue(amount))
), player::getCommandSource);
}
};
@@ -694,23 +692,30 @@ public class CarpetEventServer
{
handler.call(
() -> Arrays.asList(
((c, t) -> new BlockValue(null, world, pos)),
((c, t) -> flag>0?Value.TRUE:Value.FALSE)
(new BlockValue(null, world, pos)),
(flag>0?Value.TRUE:Value.FALSE)
), () -> CarpetServer.minecraft_server.getCommandSource().withWorld(world)
);
}
};
public static String getLoadEvent(EntityType<? extends Entity> et)
{
return "entity_loaded_" + Registry.ENTITY_TYPE.getId(et);
}
public static final Map<EntityType<?>, Event> ENTITY_LOAD= new HashMap<EntityType<?>, Event>() {{
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("entity_loaded_" + Registry.ENTITY_TYPE.getId(et), 1, true, false)
put(et, new Event(getLoadEvent(et), 1, true, false)
{
@Override
public void onEntityAction(Entity entity)
{
super.onEntityAction(entity);
handler.call(
() -> Collections.singletonList((new EntityValue(entity))),
() -> CarpetServer.minecraft_server.getCommandSource().withWorld((ServerWorld) entity.world).withLevel(CarpetSettings.runPermissionLevel)
);
}
});
});
@@ -808,12 +813,13 @@ public class CarpetEventServer
return added;
}
public boolean addEventDirectly(String event, ScriptHost host, FunctionValue function)
public void addEventDirectly(String event, ScriptHost host, FunctionValue function, List<Value> args)
{
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");
return ev.handler.addEventCallDirect(host, function);
boolean success = ev.handler.addEventCallInternal(host, function, args);
if (!success) throw new InternalExpressionException("Global event "+event+" requires "+ev.handler.reqArgs+", not "+(function.getNumParams()-((args==null)?0:args.size())));
}
private boolean canAddEvent(Event event, ScriptHost host)
@@ -836,6 +842,16 @@ public class CarpetEventServer
Messenger.m(source, "gi Removed event: " + funName + " from "+event);
return true;
}
public boolean removeEventDirectly(String event, ScriptHost host)
{
if (!Event.byName.containsKey(event))
{
return false;
}
Event.byName.get(event).handler.removeAllCalls(host.getName());
return true;
}
public void removeEventDirectly(String event, ScriptHost host, String funName)
{
@@ -109,7 +109,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);
scriptServer.events.addEventDirectly(event, this, function, null);
}
else if (funName.equals("__config"))
{
@@ -305,12 +305,12 @@ public class CarpetScriptHost extends ScriptHost
}
}
public Value callUDF(BlockPos pos, ServerCommandSource source, FunctionValue fun, List<LazyValue> argv) throws InvalidCallbackException
public Value callUDF(BlockPos pos, ServerCommandSource source, FunctionValue fun, List<Value> argv) throws InvalidCallbackException
{
if (CarpetServer.scriptServer.stopAll)
return Value.NULL;
try { // cause we can't throw checked exceptions in lambda. Left if be until need to handle these more gracefully
fun.assertArgsOk(argv.size(), (b) -> {
fun.assertArgsOk(argv, (b) -> {
throw new InternalExpressionException("");
});
}
@@ -323,7 +323,7 @@ public class CarpetScriptHost extends ScriptHost
// TODO: this is just for now - invoke would be able to invoke other hosts scripts
Context context = new CarpetContext(this, source, pos);
return fun.getExpression().evalValue(
() -> fun.lazyEval(context, Context.VOID, fun.getExpression(), fun.getToken(), argv),
() -> fun.lazyEval(context, Context.VOID, fun.getExpression(), fun.getToken(), FunctionValue.lazify(argv)),
context,
Context.VOID);
}
@@ -334,6 +334,7 @@ public class CarpetScriptHost extends ScriptHost
return Value.NULL;
}
@Override
public void onClose()
{
@@ -268,12 +268,12 @@ public class CarpetScriptServer
return true;
}
public boolean runas(ServerCommandSource source, String hostname, FunctionValue udf, List<LazyValue> argv)
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<LazyValue> argv)
public boolean runas(BlockPos origin, ServerCommandSource source, String hostname, FunctionValue udf, List<Value> argv)
{
CarpetScriptHost host = globalHost;
try
@@ -19,7 +19,7 @@ import java.util.Map;
public class EntityEventsGroup
{
private final Map<Event, Map<String, CarpetEventServer.ScheduledCall>> actions;
private final Map<Event, Map<String, CarpetEventServer.Callback>> actions;
private final Entity entity;
public EntityEventsGroup(Entity e)
{
@@ -30,35 +30,37 @@ 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.ScheduledCall> actionSet = actions.get(type);
Map<String, CarpetEventServer.Callback> actionSet = actions.get(type);
if (actionSet == null) return;
for (Iterator<Map.Entry<String, CarpetEventServer.ScheduledCall>> iterator = actionSet.entrySet().iterator(); iterator.hasNext(); )
for (Iterator<Map.Entry<String, CarpetEventServer.Callback>> iterator = actionSet.entrySet().iterator(); iterator.hasNext(); )
{
Map.Entry<String, CarpetEventServer.ScheduledCall> action = iterator.next();
Map.Entry<String, CarpetEventServer.Callback> action = iterator.next();
ScriptHost host = CarpetServer.scriptServer.getHostByName(action.getKey());
if (host == null)
{
iterator.remove();
continue;
}
type.call(action.getValue(), entity, args); // optionally remove when call failing
if (!type.call(action.getValue(), entity, args))
iterator.remove();
}
if (actionSet.isEmpty()) actions.remove(type);
}
public void addEvent(Event type, CarpetContext cc, FunctionValue fun, List<Value> extraargs)
public void addEvent(Event type, String hostName, FunctionValue fun, List<Value> extraargs)
{
if (fun != null)
{
CarpetEventServer.ScheduledCall call = type.create(cc, fun, extraargs);
CarpetEventServer.Callback call = type.create(hostName, fun, extraargs);
if (call == null)
throw new InternalExpressionException("wrong number of arguments for callback, required "+type.argcount);
actions.computeIfAbsent(type, k -> new HashMap<>()).put(cc.host.getName(), call);
actions.computeIfAbsent(type, k -> new HashMap<>()).put(hostName, call);
}
else
{
actions.computeIfAbsent(type, k -> new HashMap<>()).remove(cc.host.getName());
actions.computeIfAbsent(type, k -> new HashMap<>()).remove(hostName);
if (actions.get(type).isEmpty())
actions.remove(type);
}
@@ -105,18 +107,18 @@ public class EntityEventsGroup
argcount = args+1; // entity is not extra
byName.put(identifier, this);
}
public CarpetEventServer.ScheduledCall create(CarpetContext cc, FunctionValue function, List<Value> extraArgs)
public CarpetEventServer.Callback create(String hostName, FunctionValue function, List<Value> extraArgs)
{
if ((function.getArguments().size()-(extraArgs == null ? 0 : extraArgs.size())) != argcount)
{
return null;
}
return new CarpetEventServer.ScheduledCall(cc, function, extraArgs, 0);
return new CarpetEventServer.Callback(hostName, function, extraArgs);
}
public void call(CarpetEventServer.ScheduledCall tickCall, Entity entity, Object ... args)
public boolean call(CarpetEventServer.Callback tickCall, Entity entity, Object ... args)
{
assert args.length == argcount-1;
tickCall.execute(entity.getCommandSource(), makeArgs(entity, args));
return tickCall.execute(entity.getCommandSource(), makeArgs(entity, args));
}
protected List<Value> makeArgs(Entity entity, Object ... args)
{
@@ -640,7 +640,7 @@ 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);
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, true, false, true);
CarpetServer.scriptServer.events.scheduleCall(
(CarpetContext) c,
+37 -40
View File
@@ -1,6 +1,7 @@
package carpet.script.api;
import carpet.script.CarpetContext;
import carpet.script.CarpetEventServer;
import carpet.script.CarpetScriptHost;
import carpet.script.Expression;
import carpet.script.LazyValue;
@@ -11,7 +12,6 @@ import carpet.script.value.EntityValue;
import carpet.script.value.FunctionValue;
import carpet.script.value.ListValue;
import carpet.script.value.NBTSerializableValue;
import carpet.script.value.NullValue;
import carpet.script.value.NumericValue;
import carpet.script.value.Value;
import com.mojang.brigadier.StringReader;
@@ -29,13 +29,13 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.registry.Registry;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class Entities {
@@ -119,7 +119,7 @@ public class Entities {
try
{
entityId = Identifier.fromCommandInput(new StringReader(entityString));
EntityType type = Registry.ENTITY_TYPE.getOrEmpty(entityId).orElse(null);
EntityType<? extends Entity> type = Registry.ENTITY_TYPE.getOrEmpty(entityId).orElse(null);
if (type == null || !type.isSummonable())
return LazyValue.NULL;
}
@@ -183,12 +183,8 @@ public class Entities {
expression.addLazyFunction("entity_list", 1, (c, t, lv) ->
{
String who = lv.get(0).evalValue(c).getString();
Pair<EntityType<?>, Predicate<? super Entity>> pair = EntityValue.getPredicate(who);
if (pair == null)
{
throw new InternalExpressionException("Unknown entity selection criterion: "+who);
}
List<Entity> entityList = ((CarpetContext)c).s.getWorld().getEntitiesByType(pair.getKey(), pair.getValue());
EntityValue.EntityClassDescriptor eDesc = EntityValue.getEntityDescriptor(who);
List<Entity> entityList = ((CarpetContext)c).s.getWorld().getEntitiesByType(eDesc.directType, eDesc.filteringPredicate);
Value retval = ListValue.wrap(entityList.stream().map(EntityValue::new).collect(Collectors.toList()));
return (_c, _t ) -> retval;
});
@@ -206,13 +202,8 @@ public class Entities {
throw new InternalExpressionException("Range of 'entity_area' cannot come from a block argument");
Vec3d range = rangeLocator.vec;
Box area = new Box(center, center).expand(range.x, range.y, range.z);
Pair<EntityType<?>, Predicate<? super Entity>> pair = EntityValue.getPredicate(who);
if (pair == null)
{
throw new InternalExpressionException("Unknown entity selection criterion: "+who);
}
List<Entity> entityList = ((CarpetContext)c).s.getWorld().getEntitiesByType((EntityType<Entity>) pair.getKey(), area, pair.getValue());
EntityValue.EntityClassDescriptor eDesc = EntityValue.getEntityDescriptor(who);
List<? extends Entity> entityList = ((CarpetContext)c).s.getWorld().getEntitiesByType(eDesc.directType, area,eDesc.filteringPredicate);
Value retval = ListValue.wrap(entityList.stream().map(EntityValue::new).collect(Collectors.toList()));
return (_c, _t ) -> retval;
});
@@ -268,15 +259,36 @@ public class Entities {
return (cc, tt) -> v;
});
expression.addFunction("entity_types", (lv) ->
{
if (lv.size() > 1) throw new InternalExpressionException("'entity_types' requires one or no arguments");
String desc = (lv.size() == 1)?lv.get(0).getString():"*";
return EntityValue.getEntityDescriptor(desc).listValue;
});
expression.addLazyFunction("entity_load_handler", -1, (c, t, lv) ->
{
if (lv.size() < 3) throw new InternalExpressionException("'entity_load_handler' required the entity type, and a function to call");
String entityString = lv.get(0).evalValue(c).getString();
FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 2, true, true);
((CarpetScriptHost)c.host).getScriptServer().events.addEventDirectly(entityString, c.host, funArg.function);
};
if (c.host.isPerUser()) throw new InternalExpressionException("'entity_load_handler' can only be called in apps with global scope");
if (lv.size() < 2) throw new InternalExpressionException("'entity_load_handler' required the entity type, and a function to call");
Value entityValue = lv.get(0).evalValue(c);
List<String> descriptors = (entityValue instanceof ListValue)
? ((ListValue) entityValue).getItems().stream().map(Value::getString).collect(Collectors.toList())
: 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);
CarpetEventServer events = ((CarpetScriptHost)c.host).getScriptServer().events;
if (funArg.function == null)
{
types.forEach(et -> events.removeEventDirectly(CarpetEventServer.Event.getLoadEvent(et), c.host));
}
else
{
types.forEach(et -> events.addEventDirectly(CarpetEventServer.Event.getLoadEvent(et), c.host, funArg.function, FunctionValue.resolveArgs(funArg.args, c, t)));
}
Value ret = new NumericValue(types.size());
return (cc, tt) -> ret;
});
// or update
expression.addLazyFunction("entity_event", -1, (c, t, lv) ->
@@ -288,24 +300,9 @@ public class Entities {
throw new InternalExpressionException("First argument to entity_event should be an entity");
String what = lv.get(1).evalValue(c).getString();
Value functionValue = lv.get(2).evalValue(c);
if (functionValue instanceof NullValue)
functionValue = null;
else if (!(functionValue instanceof FunctionValue))
{
String name = functionValue.getString();
functionValue = c.host.getAssertFunction(expression.module, name);
}
FunctionValue function = (FunctionValue)functionValue;
List<Value> args = null;
if (lv.size()==4)
args = Collections.singletonList(lv.get(3).evalValue(c));
else if (lv.size()>4)
{
args = lv.subList(3, lv.size()).stream().map((vv) -> vv.evalValue(c)).collect(Collectors.toList());
}
FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 2, false, true, false);
((EntityValue) v).setEvent((CarpetContext)c, what, function, args);
((EntityValue) v).setEvent((CarpetContext)c, what, funArg.function, FunctionValue.resolveArgs(funArg.args, c, t));
return LazyValue.NULL;
});
@@ -21,9 +21,34 @@ public class FunctionArgument extends Argument
this.function = function;
this.args = args;
}
public static FunctionArgument findIn(Context c, Module module, List<LazyValue> params, int offset, boolean prematureEvaluation, boolean allowNone)
/**
* @param c context
* @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
* if the number of supplied arguments is right
* @return argument data
*/
public static FunctionArgument findIn(
Context c,
Module module,
List<LazyValue> params,
int offset,
boolean prematureEvaluation,
boolean allowNone,
boolean checkArgs)
{
Value functionValue = params.get(offset).evalValue(c);
if (functionValue.isNull())
{
if (allowNone) return new FunctionArgument(null, offset+1, null);
throw new InternalExpressionException("function argument cannot be null");
}
if (!(functionValue instanceof FunctionValue))
{
String name = functionValue.getString();
@@ -31,11 +56,14 @@ public class FunctionArgument extends Argument
}
FunctionValue fun = (FunctionValue)functionValue;
int argsize = fun.getArguments().size();
if (checkArgs)
{
int extraargs = params.size() - argsize - offset - 1;
if (extraargs < 0)
throw new InternalExpressionException("Function " + fun.getPrettyString() + " requires at least " + fun.getArguments().size() + " arguments");
if (extraargs > 0 && fun.getVarArgs() == null)
throw new InternalExpressionException("Function " + fun.getPrettyString() + " requires " + fun.getArguments().size() + " arguments");
}
List<LazyValue> lvargs = new ArrayList<>();
if (prematureEvaluation)
{
@@ -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);
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, 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,7 +4,6 @@ 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;
@@ -17,7 +16,7 @@ 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);
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);
Thread.yield();
return (cc, tt) -> thread;
@@ -28,7 +27,7 @@ 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);
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, true, false, true);
ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, functionArgument.args);
Thread.yield();
return (cc, tt) -> thread;
@@ -25,6 +25,7 @@ import net.minecraft.entity.EntityGroup;
import net.minecraft.entity.ai.brain.MemoryModuleType;
import net.minecraft.entity.ai.pathing.Path;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.packet.s2c.play.EntityPassengersSetS2CPacket;
@@ -191,117 +192,139 @@ public class EntityValue extends Value
return "entity";
}
@Override
public int hashCode()
{
return entity.hashCode();
}
public static Pair<EntityType<?>, Predicate<? super Entity>> getPredicate(String who)
public static EntityClassDescriptor getEntityDescriptor(String who)
{
Pair<EntityType<?>, Predicate<? super Entity>> res = entityPredicates.get(who);
if (res != null) return res;
return res; //TODO add more here like search by tags, or type
EntityClassDescriptor eDesc = EntityClassDescriptor.byName.get(who);
if (eDesc == null) throw new InternalExpressionException(who+" is not a valid entity descriptor");
return eDesc;
//TODO add more here like search by tags, or type
//if (who.startsWith('tag:'))
}
private static Map<String, EntityGroup> entityGroupMap = ImmutableMap.of(
"undead", EntityGroup.UNDEAD,
"arthropod", EntityGroup.ARTHROPOD,
"aquatic", EntityGroup.AQUATIC,
"regular", EntityGroup.DEFAULT,
"illager", EntityGroup.ILLAGER
);
public static class EntityClassDescriptor
{
public EntityType<?> directType;
public EntityType<? extends Entity> directType;
public Predicate<? super Entity> filteringPredicate;
public List<EntityType<?>> typeList;
EntityClassDescriptor(EntityType<?> type, Predicate<? super Entity> predicate, Stream<EntityType<?>> types)
public List<EntityType<? extends Entity>> typeList;
public Value listValue;
EntityClassDescriptor(EntityType<?> type, Predicate<? super Entity> predicate, List<EntityType<?>> types)
{
directType = type;
filteringPredicate = predicate;
typeList = types.collect(Collectors.toList());
typeList = types;
listValue = (types==null)?Value.NULL:ListValue.wrap(types.stream().map(et -> StringValue.of(nameFromRegistryId(Registry.ENTITY_TYPE.getId(et)))).collect(Collectors.toList()));
}
EntityClassDescriptor(EntityType<?> type, Predicate<? super Entity> predicate, Stream<EntityType<?>> types)
{
this(type, predicate, types.collect(Collectors.toList()));
}
public Map<String, EntityClassDescriptor> byName = new HashMap<String, EntityClassDescriptor>() {{
Stream<EntityType<?>> allTypes = Registry.ENTITY_TYPE.stream();
public final static Map<String, EntityClassDescriptor> byName = new HashMap<String, EntityClassDescriptor>() {{
List<EntityType<?>> allTypes = Registry.ENTITY_TYPE.stream().collect(Collectors.toList());
// nonliving types
Set<EntityType<?>> projectiles = Sets.newHashSet(
EntityType.ARROW, EntityType.DRAGON_FIREBALL
EntityType.ARROW, EntityType.DRAGON_FIREBALL, EntityType.FIREWORK_ROCKET,
EntityType.FIREBALL, EntityType.LLAMA_SPIT, EntityType.SMALL_FIREBALL,
EntityType.SNOWBALL, EntityType.SPECTRAL_ARROW, EntityType.EGG,
EntityType.ENDER_PEARL, EntityType.EXPERIENCE_BOTTLE, EntityType.POTION,
EntityType.TRIDENT, EntityType.WITHER_SKULL, EntityType.FISHING_BOBBER
);
Set<EntityType<?>> deads = Sets.newHashSet(
EntityType.AREA_EFFECT_CLOUD, EntityType.BOAT,
)
EntityType.AREA_EFFECT_CLOUD, EntityType.BOAT, EntityType.END_CRYSTAL,
EntityType.EVOKER_FANGS, EntityType.EXPERIENCE_ORB, EntityType.EYE_OF_ENDER,
EntityType.FALLING_BLOCK, EntityType.ITEM, EntityType.ITEM_FRAME,
EntityType.LEASH_KNOT, EntityType.LIGHTNING_BOLT, EntityType.PAINTING,
EntityType.TNT
);
Set<EntityType<?>> minecarts = Sets.newHashSet(
EntityType.MINECART, EntityType.CHEST_MINECART, EntityType.COMMAND_BLOCK_MINECART,
EntityType.FURNACE_MINECART, EntityType.HOPPER_MINECART,
EntityType.SPAWNER_MINECART, EntityType.TNT_MINECART
);
// living mob groups - non-defeault
Set<EntityType<?>> undeads = Sets.newHashSet(
EntityType.STRAY, EntityType.SKELETON, EntityType.WITHER_SKELETON,
EntityType.ZOMBIE, EntityType.DROWNED, EntityType.ZOMBIE_VILLAGER,
EntityType.ZOMBIE_HORSE, EntityType.SKELETON_HORSE, EntityType.PHANTOM,
EntityType.WITHER, EntityType.ZOGLIN, EntityType.HUSK, EntityType.ZOMBIFIED_PIGLIN
);
Set<EntityType<?>> arthropods = Sets.newHashSet(
EntityType.BEE, EntityType.ENDERMITE, EntityType.SILVERFISH, EntityType.SPIDER,
EntityType.CAVE_SPIDER
);
Set<EntityType<?>> aquatique = Sets.newHashSet(
EntityType.GUARDIAN, EntityType.TURTLE, EntityType.COD, EntityType.DOLPHIN, EntityType.PUFFERFISH,
EntityType.SALMON, EntityType.SQUID, EntityType.TROPICAL_FISH
);
Set<EntityType<?>> illagers = Sets.newHashSet(
EntityType.PILLAGER, EntityType.ILLUSIONER, EntityType.VINDICATOR, EntityType.EVOKER,
EntityType.RAVAGER, EntityType.WITCH
);
Set<EntityType<?>> living = allTypes.stream().filter(et ->
!deads.contains(et) && !projectiles.contains(et) && !minecarts.contains(et)
).collect(Collectors.toSet());
Set<EntityType<?>> regular = allTypes.stream().filter(et ->
living.contains(et) && !undeads.contains(et) && !arthropods.contains(et) && !aquatique.contains(et) && !illagers.contains(et)
).collect(Collectors.toSet());
put("*", new EntityClassDescriptor(null, e -> true, allTypes) );
put("valid", new EntityClassDescriptor(null, EntityPredicates.VALID_ENTITY, allTypes));
put("!valid", new EntityClassDescriptor(null, e -> !e.isAlive(), allTypes));
put("living", Pair.of(null, (e) -> e instanceof LivingEntity && e.isAlive(), allTypes.filter(et -> et.)));
put("!living", Pair.of(null, (e) -> !(e instanceof LivingEntity) && e.isAlive()));
put("living", new EntityClassDescriptor(null, (e) -> (e instanceof LivingEntity && e.isAlive()), allTypes.stream().filter(living::contains)));
put("!living", new EntityClassDescriptor(null, (e) -> (!(e instanceof LivingEntity) && e.isAlive()), allTypes.stream().filter(et -> !living.contains(et))));
put("projectile", Pair.of(null, (e) -> e instanceof ProjectileEntity && e.isAlive()));
put("!projectile", Pair.of(null, (e) -> !(e instanceof ProjectileEntity) && e.isAlive()));
put("projectile", new EntityClassDescriptor(null, (e) -> (e instanceof ProjectileEntity && e.isAlive()), allTypes.stream().filter(projectiles::contains)));
put("!projectile", new EntityClassDescriptor(null, (e) -> (!(e instanceof ProjectileEntity) && e.isAlive()), allTypes.stream().filter(et -> !projectiles.contains(et) && !living.contains(et))));
put("minecarts", new EntityClassDescriptor(null, (e) -> (e instanceof AbstractMinecartEntity && e.isAlive()), allTypes.stream().filter(minecarts::contains)));
put("!minecarts", new EntityClassDescriptor(null, (e) -> (!(e instanceof AbstractMinecartEntity) && e.isAlive()), allTypes.stream().filter(et -> !minecarts.contains(et) && !living.contains(et))));
// combat groups
put("arthropod", new EntityClassDescriptor(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() == EntityGroup.ARTHROPOD && e.isAlive()), allTypes.stream().filter(arthropods::contains)));
put("!arthropod", new EntityClassDescriptor(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() != EntityGroup.ARTHROPOD && e.isAlive()), allTypes.stream().filter(et -> !arthropods.contains(et) && living.contains(et))));
put("undead", new EntityClassDescriptor(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() == EntityGroup.UNDEAD && e.isAlive()), allTypes.stream().filter(undeads::contains)));
put("!undead", new EntityClassDescriptor(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() != EntityGroup.UNDEAD && e.isAlive()), allTypes.stream().filter(et -> !undeads.contains(et) && living.contains(et))));
put("aquatic", new EntityClassDescriptor(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() == EntityGroup.AQUATIC && e.isAlive()), allTypes.stream().filter(aquatique::contains)));
put("!aquatic", new EntityClassDescriptor(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() != EntityGroup.AQUATIC && e.isAlive()), allTypes.stream().filter(et -> !aquatique.contains(et) && living.contains(et))));
put("illager", new EntityClassDescriptor(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() == EntityGroup.ILLAGER && e.isAlive()), allTypes.stream().filter(illagers::contains)));
put("!illager", new EntityClassDescriptor(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() != EntityGroup.ILLAGER && e.isAlive()), allTypes.stream().filter(et -> !illagers.contains(et) && living.contains(et))));
put("regular", new EntityClassDescriptor(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() == EntityGroup.DEFAULT && e.isAlive()), allTypes.stream().filter(regular::contains)));
put("!regular", new EntityClassDescriptor(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() != EntityGroup.DEFAULT && e.isAlive()), allTypes.stream().filter(et -> !regular.contains(et) && living.contains(et))));
for (String groupStr : entityGroupMap.keySet())
{
EntityGroup group = entityGroupMap.get(groupStr);
put( groupStr, Pair.of(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() == group && e.isAlive())));
put("!"+groupStr, Pair.of(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() != group && e.isAlive())));
}
for (Identifier typeId : Registry.ENTITY_TYPE.getIds())
{
EntityType type = Registry.ENTITY_TYPE.get(typeId);
EntityType<?> type = Registry.ENTITY_TYPE.get(typeId);
String mobType = ValueConversions.simplify(typeId);
put( mobType, Pair.of(type, EntityPredicates.VALID_ENTITY));
put("!"+mobType, Pair.of(null, (e) -> e.getType() != type && e.isAlive()));
put( mobType, new EntityClassDescriptor(type, EntityPredicates.VALID_ENTITY, Stream.of(type)));
put("!"+mobType, new EntityClassDescriptor(null, (e) -> e.getType() != type && e.isAlive(), allTypes.stream().filter(et -> et != type)));
}
for (SpawnGroup catId : SpawnGroup.values())
{
String catStr = catId.getName();
put( catStr, Pair.of(null, e -> (e.getType().getSpawnGroup() == catId) && e.isAlive()));
put("!"+catStr, Pair.of(null, e -> (e.getType().getSpawnGroup() != catId) && e.isAlive()));
}
}}
}
private static final Map<String, Pair<EntityType<?>, Predicate<? super Entity>>> entityPredicates =
new HashMap<String, Pair<EntityType<?>, Predicate<? super Entity>>>()
{{
put("*", Pair.of(null, e -> true));
put("valid", Pair.of(null, EntityPredicates.VALID_ENTITY));
put("!valid", Pair.of(null, e -> !e.isAlive()));
put("living", Pair.of(null, (e) -> e instanceof LivingEntity && e.isAlive()));
put("!living", Pair.of(null, (e) -> !(e instanceof LivingEntity) && e.isAlive()));
put("projectile", Pair.of(null, (e) -> e instanceof ProjectileEntity && e.isAlive()));
put("!projectile", Pair.of(null, (e) -> !(e instanceof ProjectileEntity) && e.isAlive()));
for (String groupStr : entityGroupMap.keySet())
{
EntityGroup group = entityGroupMap.get(groupStr);
put( groupStr, Pair.of(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() == group && e.isAlive())));
put("!"+groupStr, Pair.of(null, e -> ((e instanceof LivingEntity) && ((LivingEntity) e).getGroup() != group && e.isAlive())));
}
for (Identifier typeId : Registry.ENTITY_TYPE.getIds())
{
EntityType type = Registry.ENTITY_TYPE.get(typeId);
String mobType = ValueConversions.simplify(typeId);
put( mobType, Pair.of(type, EntityPredicates.VALID_ENTITY));
put("!"+mobType, Pair.of(null, (e) -> e.getType() != type && e.isAlive()));
}
for (SpawnGroup catId : SpawnGroup.values())
{
String catStr = catId.getName();
put( catStr, Pair.of(null, e -> (e.getType().getSpawnGroup() == catId) && e.isAlive()));
put("!"+catStr, Pair.of(null, e -> (e.getType().getSpawnGroup() != catId) && e.isAlive()));
put( catStr, new EntityClassDescriptor(null, e -> ((e.getType().getSpawnGroup() == catId) && e.isAlive()), allTypes.stream().filter(et -> et.getSpawnGroup() == catId)));
put("!"+catStr, new EntityClassDescriptor(null, e -> ((e.getType().getSpawnGroup() != catId) && e.isAlive()), allTypes.stream().filter(et -> et.getSpawnGroup() != catId)));
}
}};
}
public Value get(String what, Value arg)
{
if (!(featureAccessors.containsKey(what)))
@@ -1323,7 +1346,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, fun, args);
((EntityInterface)entity).getEventContainer().addEvent(event, cc.host.getName(), fun, args);
}
@Override
@@ -24,13 +24,13 @@ import java.util.stream.Collectors;
public class FunctionValue extends Value implements Fluff.ILazyFunction
{
private Expression expression;
private Tokenizer.Token token;
private String name;
private LazyValue body;
private final Expression expression;
private final Tokenizer.Token token;
private final String name;
private final LazyValue body;
private Map<String, LazyValue> outerState;
private List<String> args;
private String varArgs;
private final List<String> args;
private final String varArgs;
private static long variantCounter = 1;
private long variant;
@@ -99,8 +99,6 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
return name.hashCode()+(int)variant;
}
@Override
public boolean equals(Object o)
{
@@ -178,7 +176,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
@Override
public LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
{
assertArgsOk(lazyParams.size(), (fixedArgs) ->{
assertArgsOk(lazyParams, (fixedArgs) ->{
if (fixedArgs) // wrong number of args for fixed args
{
throw new ExpressionException(c, e, t,
@@ -264,8 +262,9 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
return StringTag.of(getString());
}
public void assertArgsOk(int size, Consumer<Boolean> feedback)
public void assertArgsOk(List<?> list, Consumer<Boolean> feedback)
{
int size = list==null?0:list.size();
if (varArgs == null && args.size() != size) // wrong number of args for fixed args
{
feedback.accept(true);
@@ -276,4 +275,17 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
feedback.accept(false);
}
}
public static List<Value> resolveArgs(List<LazyValue> lzargs, Context c, Integer t)
{
List<Value> args = new ArrayList<>(lzargs.size());
lzargs.forEach( v -> args.add( v.evalValue(c, t)));
return args;
}
public static List<LazyValue> lazify(List<Value> args)
{
List<LazyValue> lzargs = new ArrayList<>(args.size());
args.forEach( v -> lzargs.add( (c, t) -> v));
return lzargs;
}
}