Merge pull request #523 from gnembon/entity_hooks
Entity hooks and Event rework
This commit is contained in:
20 files changed
+558
-329
No files matched your search
+46
-13
@@ -2540,20 +2540,34 @@ 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 matching specified descriptor.
|
||||
Calls to `entity_list` always fetch entities from the current world that the script executes.
|
||||
|
||||
### `entity_types(descriptor)`
|
||||
|
||||
* `*`: all entities, even `!valid`
|
||||
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. `!minecarts` matches all types that are not live, but also not minecarts. Using plural
|
||||
since `minecart` is a proper entity type on its own.
|
||||
* `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 mechanics interact with groups, like ringing a bell with illagers. All other 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`,
|
||||
@@ -2569,8 +2583,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)`
|
||||
|
||||
@@ -3243,7 +3257,26 @@ 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`, then the current entity handler, if present, is removed. Consecutive calls to `entity_load_handler` will add / subtract
|
||||
of the currently targeted entity types pool.
|
||||
|
||||
Like other global events, calls to `entity_load_handler` can only be attached in apps with global scope. Player scope makes 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.
|
||||
|
||||
@@ -24,20 +24,34 @@ 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 matching specified descriptor.
|
||||
Calls to `entity_list` always fetch entities from the current world that the script executes.
|
||||
|
||||
### `entity_types(descriptor)`
|
||||
|
||||
* `*`: all entities, even `!valid`
|
||||
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. `!minecarts` matches all types that are not live, but also not minecarts. Using plural
|
||||
since `minecart` is a proper entity type on its own.
|
||||
* `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 mechanics interact with groups, like ringing a bell with illagers. All other 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 +67,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 +741,26 @@ 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`, then the current entity handler, if present, is removed. Consecutive calls to `entity_load_handler` will add / subtract
|
||||
of the currently targeted entity types pool.
|
||||
|
||||
Like other global events, calls to `entity_load_handler` can only be attached in apps with global scope. Player scope makes 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(
|
||||
|
||||
@@ -50,7 +50,7 @@ public abstract class PlayerEntity_scarpetEventsMixin extends LivingEntity
|
||||
{
|
||||
if (PLAYER_COLLIDES_WITH_ENTITY.isNeeded() && !world.isClient)
|
||||
{
|
||||
PLAYER_COLLIDES_WITH_ENTITY.onEntityAction((ServerPlayerEntity)(Object)this, entity, null);
|
||||
PLAYER_COLLIDES_WITH_ENTITY.onEntityHandAction((ServerPlayerEntity)(Object)this, entity, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +224,7 @@ public class ServerPlayNetworkHandler_scarpetEventsMixin
|
||||
))
|
||||
private void onEntityInteract(PlayerInteractEntityC2SPacket playerInteractEntityC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
PLAYER_INTERACTS_WITH_ENTITY.onEntityAction(player, playerInteractEntityC2SPacket_1.getEntity(player.getServerWorld()), playerInteractEntityC2SPacket_1.getHand());
|
||||
PLAYER_INTERACTS_WITH_ENTITY.onEntityHandAction(player, playerInteractEntityC2SPacket_1.getEntity(player.getServerWorld()), playerInteractEntityC2SPacket_1.getHand());
|
||||
}
|
||||
|
||||
@Inject(method = "onPlayerInteractEntity", at = @At(
|
||||
@@ -234,7 +234,7 @@ public class ServerPlayNetworkHandler_scarpetEventsMixin
|
||||
private void onEntityAttack(PlayerInteractEntityC2SPacket playerInteractEntityC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
//todo add hit and hand in the future
|
||||
PLAYER_ATTACKS_ENTITY.onEntityAction(player, playerInteractEntityC2SPacket_1.getEntity(player.getServerWorld()), null);
|
||||
PLAYER_ATTACKS_ENTITY.onEntityHandAction(player, playerInteractEntityC2SPacket_1.getEntity(player.getServerWorld()), null);
|
||||
}
|
||||
|
||||
@Inject(method = "onButtonClick", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;updateLastActionTime()V"))
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.script.CarpetEventServer;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LightningEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
@@ -12,6 +15,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import static carpet.script.CarpetEventServer.Event.ENTITY_LOAD;
|
||||
import static carpet.script.CarpetEventServer.Event.LIGHTNING;
|
||||
|
||||
@Mixin(ServerWorld.class)
|
||||
@@ -30,4 +34,24 @@ public class ServerWorld_scarpetEventMixin
|
||||
if (LIGHTNING.isNeeded()) LIGHTNING.onWorldEventFlag((ServerWorld) (Object)this, blockPos, bl2?1:0);
|
||||
}
|
||||
|
||||
@Inject(method = "loadEntityUnchecked", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/world/ServerChunkManager;loadEntity(Lnet/minecraft/entity/Entity;)V"
|
||||
))
|
||||
private void onEntityAddedToWorld(Entity entity, CallbackInfo ci)
|
||||
{
|
||||
CarpetEventServer.Event event = ENTITY_LOAD.get(entity.getType());
|
||||
if (event != null)
|
||||
{
|
||||
if (event.isNeeded())
|
||||
{
|
||||
event.onEntityAction(entity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CarpetSettings.LOG.error("Failed to handle entity "+entity.getType().getTranslationKey());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import carpet.script.value.StringValue;
|
||||
import carpet.script.value.Value;
|
||||
import carpet.utils.Messenger;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
@@ -33,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;
|
||||
@@ -56,16 +56,41 @@ public class CarpetEventServer
|
||||
{
|
||||
public final List<ScheduledCall> scheduledCalls = new LinkedList<>();
|
||||
public final MinecraftServer server;
|
||||
private static final List<Value> NOARGS = Collections.emptyList();
|
||||
|
||||
public static class Callback
|
||||
{
|
||||
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==null?NOARGS:parametrizedArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used also in entity events
|
||||
* @param asSource - entity command source
|
||||
* @param runtimeArgs = options
|
||||
*/
|
||||
public boolean execute(ServerCommandSource asSource, List<Value> runtimeArgs)
|
||||
{
|
||||
if (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
|
||||
@@ -77,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;
|
||||
}
|
||||
@@ -94,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
|
||||
@@ -136,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);
|
||||
}
|
||||
@@ -177,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.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;
|
||||
}
|
||||
|
||||
@@ -211,6 +210,11 @@ public class CarpetEventServer
|
||||
public static class Event
|
||||
{
|
||||
public static final Map<String, Event> byName = new HashMap<>();
|
||||
public static List<String> publicEvents()
|
||||
{
|
||||
return byName.entrySet().stream().filter(e -> e.getValue().isPublic).map(Map.Entry::getKey).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static final Event TICK = new Event("tick", 0, true)
|
||||
{
|
||||
@Override
|
||||
@@ -252,10 +256,7 @@ public class CarpetEventServer
|
||||
handler.call( () ->
|
||||
{
|
||||
ChunkPos pos = chunk.getPos();
|
||||
return Arrays.asList(
|
||||
((c, t) -> new NumericValue(pos.x << 4)),
|
||||
((c, t) -> new NumericValue(pos.z << 4))
|
||||
);
|
||||
return Arrays.asList(new NumericValue(pos.x << 4), new NumericValue(pos.z << 4));
|
||||
}, () -> CarpetServer.minecraft_server.getCommandSource().withWorld(world)
|
||||
);
|
||||
}
|
||||
@@ -266,7 +267,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)
|
||||
@@ -274,7 +275,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)
|
||||
@@ -282,7 +283,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)
|
||||
@@ -290,12 +291,8 @@ public class CarpetEventServer
|
||||
@Override
|
||||
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))
|
||||
handler.call( () -> Arrays.asList(new EntityValue(player),
|
||||
new NumericValue(forwardSpeed), new NumericValue(strafeSpeed), new NumericValue(jumping), new NumericValue(sneaking)
|
||||
), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
@@ -308,9 +305,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),
|
||||
StringValue.of(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")
|
||||
);
|
||||
}, player::getCommandSource);
|
||||
}
|
||||
@@ -323,9 +320,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),
|
||||
StringValue.of(facing.getName())
|
||||
);
|
||||
}, player::getCommandSource);
|
||||
}
|
||||
@@ -342,16 +339,16 @@ 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),
|
||||
StringValue.of(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand"),
|
||||
new BlockValue(null, player.getServerWorld(), blockpos),
|
||||
StringValue.of(enumfacing.getName()),
|
||||
ListValue.of(
|
||||
new NumericValue(vec3d.x),
|
||||
new NumericValue(vec3d.y),
|
||||
new NumericValue(vec3d.z)
|
||||
))
|
||||
)
|
||||
);
|
||||
}, player::getCommandSource);
|
||||
}
|
||||
@@ -367,15 +364,15 @@ 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),
|
||||
StringValue.of(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand"),
|
||||
new BlockValue(null, player.getServerWorld(), blockpos),
|
||||
StringValue.of(enumfacing.getName()),
|
||||
ListValue.of(
|
||||
new NumericValue(vec3d.x),
|
||||
new NumericValue(vec3d.y),
|
||||
new NumericValue(vec3d.z)
|
||||
))
|
||||
)
|
||||
);
|
||||
}, player::getCommandSource);
|
||||
}
|
||||
@@ -386,10 +383,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),
|
||||
StringValue.of(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand"),
|
||||
new BlockValue(null, player.getServerWorld(), pos)
|
||||
), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
@@ -398,21 +395,19 @@ public class CarpetEventServer
|
||||
@Override
|
||||
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))
|
||||
), player::getCommandSource);
|
||||
handler.call(
|
||||
() -> Arrays.asList(new EntityValue(player), new BlockValue(previousBS, player.getServerWorld(), pos)),
|
||||
player::getCommandSource
|
||||
);
|
||||
}
|
||||
};
|
||||
public static final Event PLAYER_INTERACTS_WITH_ENTITY = new Event("player_interacts_with_entity", 3, false)
|
||||
{
|
||||
@Override
|
||||
public void onEntityAction(ServerPlayerEntity player, Entity entity, Hand enumhand)
|
||||
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), StringValue.of(enumhand==Hand.MAIN_HAND?"mainhand":"offhand")
|
||||
), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
@@ -420,26 +415,16 @@ public class CarpetEventServer
|
||||
{
|
||||
@Override
|
||||
public void onItemAction(ServerPlayerEntity player, Hand enumhand, ItemStack itemstack) {
|
||||
handler.call( () ->
|
||||
{
|
||||
//ItemStack itemstack = player.getStackInHand(enumhand);
|
||||
return Arrays.asList(
|
||||
((c, t) -> new EntityValue(player)),
|
||||
((c, t) -> ListValue.fromItemStack(itemstack))
|
||||
);
|
||||
}, player::getCommandSource);
|
||||
handler.call( () -> Arrays.asList(new EntityValue(player), ListValue.fromItemStack(itemstack)), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
|
||||
public static final Event PLAYER_ATTACKS_ENTITY = new Event("player_attacks_entity", 2, false)
|
||||
{
|
||||
@Override
|
||||
public void onEntityAction(ServerPlayerEntity player, Entity entity, Hand enumhand)
|
||||
public void onEntityHandAction(ServerPlayerEntity player, Entity entity, Hand enumhand)
|
||||
{
|
||||
handler.call( () -> Arrays.asList(
|
||||
((c, t) -> new EntityValue(player)),
|
||||
((c, t) -> new EntityValue(entity))
|
||||
), player::getCommandSource);
|
||||
handler.call( () -> Arrays.asList(new EntityValue(player), new EntityValue(entity)), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
public static final Event PLAYER_STARTS_SNEAKING = new Event("player_starts_sneaking", 1, false)
|
||||
@@ -447,7 +432,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)
|
||||
@@ -455,7 +440,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)
|
||||
@@ -463,7 +448,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)
|
||||
@@ -471,7 +456,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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -482,13 +467,11 @@ public class CarpetEventServer
|
||||
{
|
||||
// this.getStackInHand(this.getActiveHand()), this.activeItemStack)
|
||||
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"))
|
||||
);
|
||||
}, player::getCommandSource);
|
||||
Arrays.asList(
|
||||
new EntityValue(player),
|
||||
ListValue.fromItemStack(itemstack),
|
||||
StringValue.of(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")
|
||||
), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
public static final Event PLAYER_FINISHED_USING_ITEM = new Event("player_finishes_using_item", 3, false)
|
||||
@@ -498,13 +481,11 @@ public class CarpetEventServer
|
||||
{
|
||||
// this.getStackInHand(this.getActiveHand()), this.activeItemStack)
|
||||
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"))
|
||||
);
|
||||
}, player::getCommandSource);
|
||||
Arrays.asList(
|
||||
new EntityValue(player),
|
||||
ListValue.fromItemStack(itemstack),
|
||||
new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")
|
||||
), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
public static final Event PLAYER_DROPS_ITEM = new Event("player_drops_item", 1, false)
|
||||
@@ -512,7 +493,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)
|
||||
@@ -520,7 +501,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)
|
||||
@@ -529,13 +510,11 @@ public class CarpetEventServer
|
||||
public void onRecipeSelected(ServerPlayerEntity player, Identifier recipe, boolean fullStack)
|
||||
{
|
||||
handler.call( () ->
|
||||
{
|
||||
return Arrays.asList(
|
||||
((c, t) -> new EntityValue(player)),
|
||||
((c, t) -> new StringValue(NBTSerializableValue.nameFromRegistryId(recipe))),
|
||||
((c, t) -> new NumericValue(fullStack))
|
||||
);
|
||||
}, player::getCommandSource);
|
||||
Arrays.asList(
|
||||
new EntityValue(player),
|
||||
StringValue.of(NBTSerializableValue.nameFromRegistryId(recipe)),
|
||||
new NumericValue(fullStack)
|
||||
), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
public static final Event PLAYER_SWITCHES_SLOT = new Event("player_switches_slot", 3, false)
|
||||
@@ -545,13 +524,11 @@ public class CarpetEventServer
|
||||
{
|
||||
if (from == to) return; // initial slot update
|
||||
handler.call( () ->
|
||||
{
|
||||
return Arrays.asList(
|
||||
((c, t) -> new EntityValue(player)),
|
||||
((c, t) -> new NumericValue(from)),
|
||||
((c, t) -> new NumericValue(to))
|
||||
);
|
||||
}, player::getCommandSource);
|
||||
Arrays.asList(
|
||||
new EntityValue(player),
|
||||
new NumericValue(from),
|
||||
new NumericValue(to)
|
||||
), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
public static final Event PLAYER_SWAPS_HANDS = new Event("player_swaps_hands", 1, false)
|
||||
@@ -559,7 +536,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)
|
||||
@@ -568,14 +545,12 @@ public class CarpetEventServer
|
||||
public void onDamage(Entity target, float amount, DamageSource source)
|
||||
{
|
||||
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()))
|
||||
);
|
||||
}, target::getCommandSource);
|
||||
Arrays.asList(
|
||||
new EntityValue(target),
|
||||
new NumericValue(amount),
|
||||
StringValue.of(source.getName()),
|
||||
source.getAttacker()==null?Value.NULL:new EntityValue(source.getAttacker())
|
||||
), target::getCommandSource);
|
||||
}
|
||||
};
|
||||
public static final Event PLAYER_DEALS_DAMAGE = new Event("player_deals_damage", 3, false)
|
||||
@@ -584,23 +559,16 @@ public class CarpetEventServer
|
||||
public void onDamage(Entity target, float amount, DamageSource source)
|
||||
{
|
||||
handler.call( () ->
|
||||
{
|
||||
return Arrays.asList(
|
||||
((c, t) -> new EntityValue(source.getAttacker())),
|
||||
((c, t) -> new NumericValue(amount)),
|
||||
((c, t) -> new EntityValue(target))
|
||||
);
|
||||
}, () -> source.getAttacker().getCommandSource());
|
||||
Arrays.asList(new EntityValue(source.getAttacker()), new NumericValue(amount), new EntityValue(target)),
|
||||
() -> source.getAttacker().getCommandSource()
|
||||
);
|
||||
}
|
||||
};
|
||||
public static final Event PLAYER_COLLIDES_WITH_ENTITY = new Event("player_collides_with_entity", 2, false)
|
||||
{
|
||||
@Override
|
||||
public void onEntityAction(ServerPlayerEntity player, Entity entity, Hand enumhand) {
|
||||
handler.call( () -> Arrays.asList(
|
||||
((c, t) -> new EntityValue(player)),
|
||||
((c, t) -> new EntityValue(entity))
|
||||
), player::getCommandSource);
|
||||
public void onEntityHandAction(ServerPlayerEntity player, Entity entity, Hand enumhand) {
|
||||
handler.call( () -> Arrays.asList(new EntityValue(player), new EntityValue(entity)), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -609,7 +577,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)
|
||||
@@ -617,7 +585,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)
|
||||
@@ -631,30 +599,21 @@ public class CarpetEventServer
|
||||
Value fromDimStr = new StringValue(NBTSerializableValue.nameFromRegistryId(fromDim.getValue()));
|
||||
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)
|
||||
), player::getCommandSource);
|
||||
handler.call( () -> Arrays.asList(new EntityValue(player), fromValue, fromDimStr, toValue, toDimStr), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
public static final Event PLAYER_CONNECTS = new Event("player_connects", 1, false) {
|
||||
@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) {
|
||||
@Override
|
||||
public void onPlayerMessage(ServerPlayerEntity player, String message)
|
||||
{
|
||||
handler.call( () -> Arrays.asList(
|
||||
((c, t) -> new EntityValue(player)),
|
||||
((c, t) -> new StringValue(message))
|
||||
), player::getCommandSource);
|
||||
handler.call( () -> Arrays.asList(new EntityValue(player), new StringValue(message)), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
public static final Event STATISTICS = new Event("statistic", 4, false)
|
||||
@@ -674,10 +633,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),
|
||||
StringValue.of(NBTSerializableValue.nameFromRegistryId(Registry.STAT_TYPE.getId(stat.getType()))),
|
||||
StringValue.of(NBTSerializableValue.nameFromRegistryId(id)),
|
||||
new NumericValue(amount)
|
||||
), player::getCommandSource);
|
||||
}
|
||||
};
|
||||
@@ -688,24 +647,52 @@ 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<? 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)
|
||||
{
|
||||
@Override
|
||||
public void onEntityAction(Entity entity)
|
||||
{
|
||||
handler.call(
|
||||
() -> Collections.singletonList(new EntityValue(entity)),
|
||||
() -> CarpetServer.minecraft_server.getCommandSource().withWorld((ServerWorld) entity.world).withLevel(CarpetSettings.runPermissionLevel)
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}};
|
||||
|
||||
// on projectile thrown (arrow from bows, crossbows, tridents, snoballs, e-pearls
|
||||
|
||||
public final String name;
|
||||
|
||||
public final CallbackList handler;
|
||||
public final boolean globalOnly;
|
||||
public final boolean isPublic; // public events can be targetted with __on_<event> defs
|
||||
public Event(String name, int reqArgs, boolean isGlobalOnly)
|
||||
{
|
||||
this(name, reqArgs, isGlobalOnly, true);
|
||||
}
|
||||
public Event(String name, int reqArgs, boolean isGlobalOnly, boolean isPublic)
|
||||
{
|
||||
this.name = name;
|
||||
this.handler = new CallbackList(reqArgs);
|
||||
this.globalOnly = isGlobalOnly;
|
||||
this.isPublic = isPublic;
|
||||
byName.put(name, this);
|
||||
}
|
||||
public boolean isNeeded()
|
||||
@@ -724,7 +711,8 @@ public class CarpetEventServer
|
||||
public void onBlockHit(ServerPlayerEntity player, Hand enumhand, BlockHitResult hitRes) { }
|
||||
public void onBlockBroken(ServerPlayerEntity player, BlockPos pos, BlockState previousBS) { }
|
||||
public void onBlockPlaced(ServerPlayerEntity player, BlockPos pos, Hand enumhand, ItemStack itemstack) { }
|
||||
public void onEntityAction(ServerPlayerEntity player, Entity entity, Hand enumhand) { }
|
||||
public void onEntityHandAction(ServerPlayerEntity player, Entity entity, Hand enumhand) { }
|
||||
public void onEntityAction(Entity entity) { }
|
||||
public void onDimensionChange(ServerPlayerEntity player, Vec3d from, Vec3d to, RegistryKey<World> fromDim, RegistryKey<World> dimTo) {}
|
||||
public void onDamage(Entity target, float amount, DamageSource source) { }
|
||||
public void onRecipeSelected(ServerPlayerEntity player, Identifier recipe, boolean fullStack) {}
|
||||
@@ -780,12 +768,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==null?NOARGS: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)
|
||||
@@ -808,6 +797,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);
|
||||
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, true, false, true);
|
||||
|
||||
CarpetServer.scriptServer.events.scheduleCall(
|
||||
(CarpetContext) c,
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package carpet.script.api;
|
||||
|
||||
import carpet.script.CarpetContext;
|
||||
import carpet.script.CarpetEventServer;
|
||||
import carpet.script.CarpetScriptHost;
|
||||
import carpet.script.Expression;
|
||||
import carpet.script.LazyValue;
|
||||
import carpet.script.argument.FunctionArgument;
|
||||
import carpet.script.argument.Vector3Argument;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
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;
|
||||
@@ -27,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 {
|
||||
@@ -117,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;
|
||||
}
|
||||
@@ -181,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;
|
||||
});
|
||||
@@ -204,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;
|
||||
});
|
||||
@@ -266,6 +259,37 @@ 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 (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) ->
|
||||
{
|
||||
@@ -275,24 +299,10 @@ public class Entities {
|
||||
if (!(v instanceof EntityValue))
|
||||
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());
|
||||
}
|
||||
|
||||
((EntityValue) v).setEvent((CarpetContext)c, what, function, args);
|
||||
FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 2, false, true, false);
|
||||
|
||||
((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)
|
||||
|
||||
/**
|
||||
* @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();
|
||||
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");
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
|
||||
@@ -15,6 +15,7 @@ import carpet.script.EntityEventsGroup;
|
||||
import carpet.script.argument.Vector3Argument;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.entity.SpawnGroup;
|
||||
@@ -24,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;
|
||||
@@ -70,15 +72,18 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static carpet.script.value.NBTSerializableValue.nameFromRegistryId;
|
||||
import static carpet.utils.MobAI.genericJump;
|
||||
@@ -187,62 +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
|
||||
);
|
||||
|
||||
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())
|
||||
public static class EntityClassDescriptor
|
||||
{
|
||||
public EntityType<? extends Entity> directType;
|
||||
public Predicate<? super Entity> filteringPredicate;
|
||||
public List<EntityType<? extends Entity>> typeList;
|
||||
public Value listValue;
|
||||
EntityClassDescriptor(EntityType<?> type, Predicate<? super Entity> predicate, List<EntityType<?>> types)
|
||||
{
|
||||
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())));
|
||||
directType = type;
|
||||
filteringPredicate = predicate;
|
||||
typeList = types;
|
||||
listValue = (types==null)?Value.NULL:ListValue.wrap(types.stream().map(et -> StringValue.of(nameFromRegistryId(Registry.ENTITY_TYPE.getId(et)))).collect(Collectors.toList()));
|
||||
}
|
||||
for (Identifier typeId : Registry.ENTITY_TYPE.getIds())
|
||||
EntityClassDescriptor(EntityType<?> type, Predicate<? super Entity> predicate, Stream<EntityType<?>> types)
|
||||
{
|
||||
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()));
|
||||
this(type, predicate, types.collect(Collectors.toList()));
|
||||
}
|
||||
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()));
|
||||
}
|
||||
}};
|
||||
|
||||
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.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.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", 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", 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 (Identifier typeId : Registry.ENTITY_TYPE.getIds())
|
||||
{
|
||||
EntityType<?> type = Registry.ENTITY_TYPE.get(typeId);
|
||||
String mobType = ValueConversions.simplify(typeId);
|
||||
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, 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)))
|
||||
@@ -1264,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,16 +262,30 @@ 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)
|
||||
{
|
||||
if (varArgs == null && args.size() != size) // wrong number of args for fixed args
|
||||
int size = list.size();
|
||||
if (varArgs == null && args.size() != size) // wrong number of args for fixed args
|
||||
{
|
||||
feedback.accept(true);
|
||||
|
||||
}
|
||||
else if (varArgs != null && args.size() > size) // too few args for varargs
|
||||
else if (varArgs != null && args.size() > size) // too few args for varargs
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -10,15 +10,18 @@ import net.minecraft.nbt.Tag;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.Math.abs;
|
||||
|
||||
public class NumericValue extends Value
|
||||
{
|
||||
private Double value;
|
||||
private final Double value;
|
||||
private Long longValue;
|
||||
final static double epsilon = 1024*Double.MIN_VALUE;
|
||||
private final static double epsilon = 32*((7*0.1)*10-7);
|
||||
private final static MathContext displayRounding = new MathContext(12, RoundingMode.HALF_EVEN);
|
||||
|
||||
public static NumericValue asNumber(Value v1, String id)
|
||||
{
|
||||
@@ -46,7 +49,8 @@ public class NumericValue extends Value
|
||||
{
|
||||
if (value.isInfinite()) return "INFINITY";
|
||||
if (value.isNaN()) return "NaN";
|
||||
return BigDecimal.valueOf(value).stripTrailingZeros().toPlainString();
|
||||
// dobules have 16 point precision, 12 is plenty to display
|
||||
return BigDecimal.valueOf(value).round(displayRounding).stripTrailingZeros().toPlainString();
|
||||
}
|
||||
catch (NumberFormatException exc)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user