diff --git a/src/main/java/carpet/commands/ScriptCommand.java b/src/main/java/carpet/commands/ScriptCommand.java index ec3f6944..fd0493f3 100644 --- a/src/main/java/carpet/commands/ScriptCommand.java +++ b/src/main/java/carpet/commands/ScriptCommand.java @@ -15,7 +15,6 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.minecraft.block.Block; @@ -26,7 +25,6 @@ import net.minecraft.command.arguments.BlockStateArgument; import net.minecraft.command.arguments.BlockStateArgumentType; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.block.entity.BlockEntity; -import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Clearable; import net.minecraft.util.math.BlockPos; import net.minecraft.server.world.ServerWorld; @@ -305,7 +303,7 @@ public class ScriptCommand Messenger.m(source, "w Handlers for "+event.name+": "); shownEvent = true; } - Messenger.m(source, "w - "+c.udf+(c.host==null?"":" (from "+c.host+")")); + Messenger.m(source, "w - "+c.function +(c.host==null?"":" (from "+c.host+")")); } } return 1; diff --git a/src/main/java/carpet/fakes/EntityInterface.java b/src/main/java/carpet/fakes/EntityInterface.java index 7a192b30..e5936b36 100644 --- a/src/main/java/carpet/fakes/EntityInterface.java +++ b/src/main/java/carpet/fakes/EntityInterface.java @@ -1,22 +1,10 @@ package carpet.fakes; -import carpet.script.CarpetContext; -import carpet.script.CarpetEventServer; -import carpet.script.value.FunctionValue; -import carpet.script.value.Value; -import net.minecraft.entity.damage.DamageSource; - -import java.util.List; +import carpet.script.EntityEventsGroup; public interface EntityInterface { float getMainYaw(float partialTicks); - //scarpet part - void onDeathCallback(String reason); - void setDeathCallback(CarpetContext cc, FunctionValue function, List extraArgs); - void onDamageCallback(float amount, DamageSource source); - void setDamageCallback(CarpetContext cc, FunctionValue function, List extraArgs); - void setRemovedCallback(CarpetContext cc, FunctionValue function, List extraArgs); - void setTickCallback(CarpetContext cc, FunctionValue function, List extraArgs); - CarpetEventServer.ScheduledCall getTickCallback(); + + EntityEventsGroup getEventContainer(); } diff --git a/src/main/java/carpet/mixins/DamageTracker_scarpetEventMixin.java b/src/main/java/carpet/mixins/DamageTracker_scarpetEventMixin.java index d2b1a68c..6f6a7d62 100644 --- a/src/main/java/carpet/mixins/DamageTracker_scarpetEventMixin.java +++ b/src/main/java/carpet/mixins/DamageTracker_scarpetEventMixin.java @@ -1,6 +1,7 @@ package carpet.mixins; import carpet.fakes.EntityInterface; +import carpet.script.EntityEventsGroup; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageTracker; @@ -19,6 +20,6 @@ public class DamageTracker_scarpetEventMixin @Inject(method = "onDamage", at = @At("HEAD")) private void onDamageTaken(DamageSource damageSource_1, float float_1, float float_2, CallbackInfo ci) { - ((EntityInterface)entity).onDamageCallback(float_2, damageSource_1); + ((EntityInterface)entity).getEventContainer().onEvent(EntityEventsGroup.EntityEventType.ON_DAMAGE, entity, float_2, damageSource_1); } } diff --git a/src/main/java/carpet/mixins/Entity_scarpetEventsMixin.java b/src/main/java/carpet/mixins/Entity_scarpetEventsMixin.java index d6abc1e1..c6306a9a 100644 --- a/src/main/java/carpet/mixins/Entity_scarpetEventsMixin.java +++ b/src/main/java/carpet/mixins/Entity_scarpetEventsMixin.java @@ -1,96 +1,37 @@ package carpet.mixins; -import carpet.CarpetServer; import carpet.fakes.EntityInterface; -import carpet.script.CarpetContext; -import carpet.script.CarpetEventServer; -import carpet.script.value.FunctionValue; -import carpet.script.value.Value; +import carpet.script.EntityEventsGroup; import net.minecraft.entity.Entity; -import net.minecraft.entity.damage.DamageSource; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.List; - @Mixin(Entity.class) public abstract class Entity_scarpetEventsMixin implements EntityInterface { @Shadow public boolean removed; - private CarpetEventServer.ScheduledCall deathCall; - private CarpetEventServer.ScheduledCall removeCall; - private CarpetEventServer.ScheduledCall tickCall; - private CarpetEventServer.ScheduledCall damageCall; + + private EntityEventsGroup events = new EntityEventsGroup(); @Override - public void setDeathCallback(CarpetContext cc, FunctionValue function, List extraArgs) + public EntityEventsGroup getEventContainer() { - deathCall = CarpetServer.scriptServer.events.makeDeathCall(cc, function, extraArgs); + return events; } - @Override - public void setRemovedCallback(CarpetContext cc, FunctionValue function, List extraArgs) - { - removeCall = CarpetServer.scriptServer.events.makeRemovedCall(cc, function, extraArgs); - } - - @Override - public void setTickCallback(CarpetContext cc, FunctionValue function, List extraArgs) - { - tickCall = CarpetServer.scriptServer.events.makeTickCall(cc, function, extraArgs); - } - - @Override - public CarpetEventServer.ScheduledCall getTickCallback() - { - return tickCall; - } - - @Override - public void setDamageCallback(CarpetContext cc, FunctionValue function, List extraArgs) - { - damageCall = CarpetServer.scriptServer.events.makeDamageCall(cc, function, extraArgs); - } - - - @Override - public void onDeathCallback(String reason) - { - if (deathCall != null) - { - CarpetServer.scriptServer.events.onEntityDeath(deathCall, (Entity)(Object)this, reason); - } - } - - @Override - public void onDamageCallback(float amount, DamageSource source) - { - if (damageCall != null) - { - CarpetServer.scriptServer.events.onEntityDamage(damageCall, (Entity)(Object)this, amount, source); - } - } - - @Inject(method = "tick", at = @At("HEAD")) private void onTickCall(CallbackInfo ci) { - if (tickCall != null) - { - CarpetServer.scriptServer.events.onEntityTick(tickCall, (Entity) (Object) this); - } + events.onEvent(EntityEventsGroup.EntityEventType.ON_TICK, (Entity) (Object) this); } @Inject(method = "remove", at = @At("HEAD")) private void onRemove(CallbackInfo ci) { - if (!removed && removeCall != null) - { - CarpetServer.scriptServer.events.onEntityRemoved(removeCall, (Entity)(Object)this); - } + if (!removed) events.onEvent(EntityEventsGroup.EntityEventType.ON_REMOVED, (Entity) (Object) this); } } diff --git a/src/main/java/carpet/mixins/FallingBlockEntity_scarpetEventsMixin.java b/src/main/java/carpet/mixins/FallingBlockEntity_scarpetEventsMixin.java index f7f65b26..9fc3fd7b 100644 --- a/src/main/java/carpet/mixins/FallingBlockEntity_scarpetEventsMixin.java +++ b/src/main/java/carpet/mixins/FallingBlockEntity_scarpetEventsMixin.java @@ -1,23 +1,28 @@ package carpet.mixins; -import carpet.CarpetServer; import carpet.fakes.EntityInterface; +import carpet.script.EntityEventsGroup; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; import net.minecraft.entity.FallingBlockEntity; +import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(FallingBlockEntity.class) -public class FallingBlockEntity_scarpetEventsMixin +public abstract class FallingBlockEntity_scarpetEventsMixin extends Entity { + public FallingBlockEntity_scarpetEventsMixin(EntityType type, World world) + { + super(type, world); + } + @Inject(method = "tick", at = @At("HEAD")) private void onTickCall(CallbackInfo ci) { - if (((EntityInterface)this).getTickCallback() != null) - { - CarpetServer.scriptServer.events.onEntityTick(((EntityInterface)this).getTickCallback(), (Entity) (Object) this); - } + // calling extra on_tick because falling blocks do not fall back to super tick call + ((EntityInterface)this).getEventContainer().onEvent(EntityEventsGroup.EntityEventType.ON_TICK, this); } } diff --git a/src/main/java/carpet/mixins/LivingEntity_scarpetEventsMixin.java b/src/main/java/carpet/mixins/LivingEntity_scarpetEventsMixin.java index ee51d29e..8ca20980 100644 --- a/src/main/java/carpet/mixins/LivingEntity_scarpetEventsMixin.java +++ b/src/main/java/carpet/mixins/LivingEntity_scarpetEventsMixin.java @@ -1,6 +1,7 @@ package carpet.mixins; import carpet.fakes.EntityInterface; +import carpet.script.EntityEventsGroup; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; @@ -12,12 +13,17 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(LivingEntity.class) -public abstract class LivingEntity_scarpetEventsMixin +public abstract class LivingEntity_scarpetEventsMixin extends Entity { + public LivingEntity_scarpetEventsMixin(EntityType type, World world) + { + super(type, world); + } + @Inject(method = "onDeath", at = @At("HEAD")) private void onDeathCall(DamageSource damageSource_1, CallbackInfo ci) { - ((EntityInterface)this).onDeathCallback(damageSource_1.name); + ((EntityInterface)this).getEventContainer().onEvent(EntityEventsGroup.EntityEventType.ON_DEATH, this, damageSource_1.name); } } diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java index fee7cff4..1462b619 100644 --- a/src/main/java/carpet/script/CarpetEventServer.java +++ b/src/main/java/carpet/script/CarpetEventServer.java @@ -9,7 +9,6 @@ import carpet.script.value.NumericValue; import carpet.script.value.StringValue; import carpet.script.value.Value; import net.minecraft.block.BlockState; -import net.minecraft.entity.damage.DamageSource; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.entity.Entity; import net.minecraft.server.network.ServerPlayerEntity; @@ -33,6 +32,7 @@ import java.util.Map; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class CarpetEventServer { @@ -41,54 +41,56 @@ public class CarpetEventServer public static class Callback { public String host; - public FunctionValue udf; + public FunctionValue function; - public Callback(String host, FunctionValue udf) + public Callback(String host, FunctionValue function) { this.host = host; - this.udf = udf; + this.function = function; } @Override public String toString() { - return udf.getString()+((host==null)?"":"(from "+host+")"); + return function.getString()+((host==null)?"":"(from "+host+")"); } } public static class ScheduledCall extends Callback { - public List args; - public ServerCommandSource context_source; - public BlockPos context_origin; + public List args; + private CarpetContext ctx; public long dueTime; - public ScheduledCall(CarpetContext context, FunctionValue udf, List args, long dueTime) + public ScheduledCall(CarpetContext context, FunctionValue function, List args, long dueTime) { - super(context.host.getName(), udf); + super(context.host.getName(), function); this.args = args; - this.context_source = context.s; - this.context_origin = context.origin; + this.ctx = context; this.dueTime = dueTime; } public void execute() { - CarpetServer.scriptServer.runas(context_origin, context_source, host, udf, args); + CarpetServer.scriptServer.runas(ctx.origin, ctx.s, host, function, lazify(args)); } - public void execute(List args) + public void execute(List args) { - if (this.args == null) - CarpetServer.scriptServer.runas(context_origin, context_source, host, udf, args); + if (this.args == null || this.args.isEmpty()) + CarpetServer.scriptServer.runas(ctx.origin, ctx.s, host, function, lazify(args)); else { - List combinedArgs = new ArrayList<>(); + List combinedArgs = new ArrayList<>(); combinedArgs.addAll(args); combinedArgs.addAll(this.args); - CarpetServer.scriptServer.runas(context_origin, context_source, host, udf, combinedArgs); + CarpetServer.scriptServer.runas(ctx.origin, ctx.s, host, function, lazify(combinedArgs)); } } + private List lazify(List args) + { + return args.stream().map(v -> (LazyValue) (c, t) -> v ).collect(Collectors.toList()); + } } public static class CallbackList @@ -110,7 +112,7 @@ public class CarpetEventServer List argv = argumentSupplier.get(); // empty for onTickDone ServerCommandSource source = cmdSourceSupplier.get(); assert argv.size() == reqArgs; - callList.removeIf(call -> !CarpetServer.scriptServer.runas(source, call.host, call.udf, argv)); // this actually does the calls + callList.removeIf(call -> !CarpetServer.scriptServer.runas(source, call.host, call.function, argv)); // this actually does the calls } } public boolean addEventCall(String hostName, String funName) @@ -148,7 +150,7 @@ public class CarpetEventServer public void removeEventCall(String hostName, String funName) { - callList.removeIf((c)-> c.udf.getString().equals(funName) && ( hostName == null || c.host.equalsIgnoreCase(hostName) ) ); + callList.removeIf((c)-> c.function.getString().equals(funName) && ( hostName == null || c.host.equalsIgnoreCase(hostName) ) ); } public void removeAllCalls(String hostName) @@ -460,7 +462,7 @@ public class CarpetEventServer } } - public void scheduleCall(CarpetContext context, FunctionValue function, List args, long due) + public void scheduleCall(CarpetContext context, FunctionValue function, List args, long due) { scheduledCalls.add(new ScheduledCall(context, function, args, due)); } @@ -510,60 +512,4 @@ public class CarpetEventServer } return Pair.of(null, funName); } - - private ScheduledCall makeEventCall(CarpetContext cc, FunctionValue function, List extraArgs, int argCount) - { - if (function == null || (function.getArguments().size()-(extraArgs == null ? 0 : extraArgs.size())) != argCount) - { - // call won't match arguments - return null; - } - List lazyArgs = null; - if (extraArgs != null) - { - lazyArgs = new ArrayList<>(); - for (Value v : extraArgs) - lazyArgs.add( (c, t) -> v); - } - return new ScheduledCall(cc, function, lazyArgs, 0); - } - - public ScheduledCall makeDeathCall(CarpetContext cc, FunctionValue function, List extraArgs) - { - return makeEventCall(cc, function, extraArgs, 2); - } - public ScheduledCall makeRemovedCall(CarpetContext cc, FunctionValue function, List extraArgs) - { - return makeEventCall(cc, function, extraArgs, 1); - } - public ScheduledCall makeTickCall(CarpetContext cc, FunctionValue function, List extraArgs) - { - return makeEventCall(cc, function, extraArgs, 1); - } - public ScheduledCall makeDamageCall(CarpetContext cc, FunctionValue function, List extraArgs) - { - return makeEventCall(cc, function, extraArgs, 4); - } - - public void onEntityDeath(ScheduledCall call, Entity e, String reason) - { - call.execute( Arrays.asList( (c, t)-> new EntityValue(e), (c, t)-> new StringValue(reason))); - } - public void onEntityRemoved(ScheduledCall removeCall, Entity entity) - { - removeCall.execute(Collections.singletonList((c, t) -> new EntityValue(entity))); - } - public void onEntityTick(ScheduledCall tickCall, Entity entity) - { - tickCall.execute(Collections.singletonList((c, t) -> new EntityValue(entity))); - } - public void onEntityDamage(ScheduledCall call, Entity e, float amount, DamageSource source) - { - call.execute(Arrays.asList( - (c, t) -> new EntityValue(e), - (c, t) -> new NumericValue(amount), - (c, t) -> new StringValue(source.getName()), - (c, t) -> source.getAttacker()==null?Value.NULL:new EntityValue(source.getAttacker()) - )); - } } diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 5a0672cc..f984e9a3 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -3084,11 +3084,11 @@ public class CarpetExpression FunctionValue function = (FunctionValue)functionValue; CarpetContext cc = (CarpetContext)c; - List args = new ArrayList<>(); + List args = new ArrayList<>(); for (int i=2; i < lv.size(); i++) { Value arg = lv.get(i).evalValue(cc); - args.add( (_c, _t) -> arg); + args.add(arg); } if (function.getArguments().size() != args.size()) throw new InternalExpressionException("Function "+function.getString()+" takes "+ diff --git a/src/main/java/carpet/script/Context.java b/src/main/java/carpet/script/Context.java index 2fd665f8..fb9d5ff2 100644 --- a/src/main/java/carpet/script/Context.java +++ b/src/main/java/carpet/script/Context.java @@ -3,7 +3,6 @@ package carpet.script; import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.function.Consumer; public class Context { @@ -20,7 +19,7 @@ public class Context public Map variables = new HashMap<>(); - protected ScriptHost host; + public ScriptHost host; Context(ScriptHost host) { diff --git a/src/main/java/carpet/script/EntityEventsGroup.java b/src/main/java/carpet/script/EntityEventsGroup.java new file mode 100644 index 00000000..da753e48 --- /dev/null +++ b/src/main/java/carpet/script/EntityEventsGroup.java @@ -0,0 +1,126 @@ +package carpet.script; + +import carpet.CarpetServer; +import carpet.script.exception.InternalExpressionException; +import carpet.script.value.EntityValue; +import carpet.script.value.FunctionValue; +import carpet.script.value.NumericValue; +import carpet.script.value.StringValue; +import carpet.script.value.Value; +import net.minecraft.entity.Entity; +import net.minecraft.entity.damage.DamageSource; + +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class EntityEventsGroup +{ + private Map> actions; + public EntityEventsGroup() + { + actions = new EnumMap<>(EntityEventType.class); + } + + public void onEvent(EntityEventType type, Entity entity, Object ... args) + { + if (actions.isEmpty()) return; // most of the cases, trying to be nice + Map actionSet = actions.get(type); + if (actionSet == null) return; + + for (Iterator> iterator = actionSet.entrySet().iterator(); iterator.hasNext(); ) + { + Map.Entry 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 (actionSet.isEmpty()) actions.remove(type); + } + + public void addEvent(EntityEventType type, CarpetContext cc, FunctionValue fun, List extraargs) + { + if (fun != null) + { + CarpetEventServer.ScheduledCall call = type.create(cc, 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); + } + else + { + actions.computeIfAbsent(type, k -> new HashMap<>()).remove(cc.host.getName()); + if (actions.get(type).isEmpty()) + actions.remove(type); + } + } + + + public enum EntityEventType + { + ON_DEATH("on_death", 1) + { + @Override + public List makeArgs(Entity entity, Object... providedArgs) + { + return Arrays.asList( + new EntityValue(entity), + new StringValue((String)providedArgs[0]) + ); + } + }, + ON_REMOVED("on_removed", 0), + ON_TICK("on_tick", 0), + ON_DAMAGE("on_damaged", 2) + { + @Override + public List makeArgs(Entity entity, Object... providedArgs) + { + float amount = (Float)providedArgs[0]; + DamageSource source = (DamageSource)providedArgs[1]; + return Arrays.asList( + new EntityValue(entity), + new NumericValue(amount), + new StringValue(source.getName()), + source.getAttacker()==null?Value.NULL:new EntityValue(source.getAttacker()) + ); + } + }; + + public static Map byName = Arrays.stream(EntityEventType.values()).collect(Collectors.toMap(ev -> ev.id, ev -> ev)); + + public int argcount; + public String id; + EntityEventType(String identifier, int args) + { + id = identifier; + argcount = args+1; // entity is not extra + } + public CarpetEventServer.ScheduledCall create(CarpetContext cc, FunctionValue function, List extraArgs) + { + if ((function.getArguments().size()-(extraArgs == null ? 0 : extraArgs.size())) != argcount) + { + return null; + } + return new CarpetEventServer.ScheduledCall(cc, function, extraArgs, 0); + } + public void call(CarpetEventServer.ScheduledCall tickCall, Entity entity, Object ... args) + { + assert args.length == argcount-1; + tickCall.execute(makeArgs(entity, args)); + } + protected List makeArgs(Entity entity, Object ... args) + { + return Collections.singletonList(new EntityValue(entity)); + }; + } +} diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java index eae7f115..f78eb427 100644 --- a/src/main/java/carpet/script/value/EntityValue.java +++ b/src/main/java/carpet/script/value/EntityValue.java @@ -5,7 +5,7 @@ import carpet.fakes.ItemEntityInterface; import carpet.fakes.MobEntityInterface; import carpet.helpers.Tracer; import carpet.script.CarpetContext; -import carpet.script.Fluff; +import carpet.script.EntityEventsGroup; import carpet.script.exception.InternalExpressionException; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -775,17 +775,11 @@ public class EntityValue extends Value // "nbt" <-big one, for now use run('data merge entity ... }}; - public void setEvent(CarpetContext cc, String event, FunctionValue fun, List args) + public void setEvent(CarpetContext cc, String eventName, FunctionValue fun, List args) { - if (!(events.containsKey(event))) - throw new InternalExpressionException("Unknown entity event: " + event); - events.get(event).accept(cc, entity, fun, args); + EntityEventsGroup.EntityEventType event = EntityEventsGroup.EntityEventType.byName.get(eventName); + if (event == null) + throw new InternalExpressionException("Unknown entity event: " + eventName); + ((EntityInterface)entity).getEventContainer().addEvent(event, cc, fun, args); } - - private static Map>> events = new HashMap>>() {{ - put("on_death", (c, e, f, l) -> ((EntityInterface)e).setDeathCallback(c, f, l)); - put("on_removed", (c, e, f, l) -> ((EntityInterface)e).setRemovedCallback(c, f, l)); - put("on_tick", (c, e, f, l) -> ((EntityInterface)e).setTickCallback(c, f, l)); - put("on_damaged", (c, e, f, l) -> ((EntityInterface)e).setDamageCallback(c, f, l)); - }}; }