diff --git a/src/main/java/carpet/CarpetServer.java b/src/main/java/carpet/CarpetServer.java index c5aa40a0..f54a66f3 100644 --- a/src/main/java/carpet/CarpetServer.java +++ b/src/main/java/carpet/CarpetServer.java @@ -11,6 +11,7 @@ import carpet.commands.DistanceCommand; import carpet.commands.DrawCommand; import carpet.commands.InfoCommand; import carpet.commands.LogCommand; +import carpet.commands.MobAICommand; import carpet.commands.PerimeterInfoCommand; import carpet.commands.PlayerCommand; import carpet.commands.ScriptCommand; @@ -22,6 +23,7 @@ import carpet.script.CarpetScriptServer; import carpet.settings.CarpetSettings; import carpet.settings.SettingsManager; import carpet.utils.HUDController; +import carpet.utils.MobAI; import com.mojang.brigadier.CommandDispatcher; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.MinecraftServer; @@ -59,6 +61,7 @@ public class CarpetServer // static for now - easier to handle all around the co e.onServerLoaded(server); }); scriptServer = new CarpetScriptServer(); + MobAI.resetTrackers(); } public static void tick(MinecraftServer server) @@ -88,6 +91,7 @@ public class CarpetServer // static for now - easier to handle all around the co PerimeterInfoCommand.register(dispatcher); DrawCommand.register(dispatcher); ScriptCommand.register(dispatcher); + MobAICommand.register(dispatcher); extensions.forEach(e -> e.registerCommands(dispatcher)); //TestCommand.register(dispatcher); } diff --git a/src/main/java/carpet/commands/MobAICommand.java b/src/main/java/carpet/commands/MobAICommand.java new file mode 100644 index 00000000..f099ac4c --- /dev/null +++ b/src/main/java/carpet/commands/MobAICommand.java @@ -0,0 +1,42 @@ +package carpet.commands; + +import carpet.settings.CarpetSettings; +import carpet.utils.MobAI; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.minecraft.command.arguments.EntitySummonArgumentType; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.util.registry.Registry; + +import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; +import static net.minecraft.server.command.CommandSource.suggestMatching; + +public class MobAICommand +{ + public static void register(CommandDispatcher dispatcher) + { + LiteralArgumentBuilder command = literal("track"). + requires((player) -> CarpetSettings.commandTrackAI). + then(argument("entity type", EntitySummonArgumentType.entitySummon()). + + suggests( (c, b) -> suggestMatching(MobAI.availbleTypes(), b)). + then(literal("clear").executes( (c) -> + { + MobAI.clearTracking(Registry.ENTITY_TYPE.get(EntitySummonArgumentType.getEntitySummon(c, "entity type"))); + return 1; + } + )). + then(argument("aspect", StringArgumentType.word()). + suggests( (c, b) -> suggestMatching(MobAI.availableFor(Registry.ENTITY_TYPE.get(EntitySummonArgumentType.getEntitySummon(c, "entity type"))),b)). + executes( (c) -> { + MobAI.startTracking( + Registry.ENTITY_TYPE.get(EntitySummonArgumentType.getEntitySummon(c, "entity type")), + MobAI.TrackingType.byName(StringArgumentType.getString(c, "aspect")) + ); + return 1; + }))); + dispatcher.register(command); + } +} diff --git a/src/main/java/carpet/mixins/VillagerEntity_aiMixin.java b/src/main/java/carpet/mixins/VillagerEntity_aiMixin.java new file mode 100644 index 00000000..637667b7 --- /dev/null +++ b/src/main/java/carpet/mixins/VillagerEntity_aiMixin.java @@ -0,0 +1,80 @@ +package carpet.mixins; + +import carpet.utils.Messenger; +import carpet.utils.MobAI; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.ai.brain.Activity; +import net.minecraft.entity.ai.brain.MemoryModuleType; +import net.minecraft.entity.passive.AbstractTraderEntity; +import net.minecraft.entity.passive.VillagerEntity; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Timestamp; +import net.minecraft.world.World; +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.Optional; + +@Mixin(VillagerEntity.class) +public abstract class VillagerEntity_aiMixin extends AbstractTraderEntity +{ + @Shadow protected abstract boolean hasSeenGolemRecently(long long_1); + + @Inject(method = "tick", at = @At("HEAD")) + private void ontick(CallbackInfo ci) + { + if (MobAI.isTracking(this, MobAI.TrackingType.IRON_GOLEM_SPAWNING) && !getEntityWorld().isClient()) + { + long time; + Optional optional_1 = this.brain.getOptionalMemory(MemoryModuleType.GOLEM_LAST_SEEN_TIME); + if (!optional_1.isPresent()) { + time = 0; + } else { + Long long_2 = optional_1.get(); + time = long_2+600 - getEntityWorld().getTime(); + } + boolean recentlySeen = hasSeenGolemRecently(getEntityWorld().getTime()); + Optional optional_11 = this.brain.getOptionalMemory(MemoryModuleType.LAST_SLEPT); + Optional optional_22 = this.brain.getOptionalMemory(MemoryModuleType.LAST_WORKED_AT_POI); + boolean work = false; + boolean sleep = false; + boolean panic = this.brain.hasActivity(Activity.PANIC); + long currentTime = this.world.getTime(); + if (optional_11.isPresent()) { + sleep = (currentTime - optional_11.get().getTime()) < 24000L; + } + if (optional_22.isPresent()) { + work = (currentTime - optional_22.get().getTime()) < 36000L; + } + + this.setCustomName(Messenger.c( + (sleep?"eb ":"fb ")+"\u263d ", + (work?"eb ":"fb ")+"\u2692 ",//"\u26CF ", + (panic?"lb ":"fb ")+"\u2623 ",//"\u2622 \u2620 \u26A1 ", + (recentlySeen?"rb ":"lb ")+time )); + this.setCustomNameVisible(true); + } + } + + @Inject(method = "summonGolem", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/util/math/Box;expand(DDD)Lnet/minecraft/util/math/Box;", + shift = At.Shift.AFTER + )) + private void particleIt(long long_1, int int_1, CallbackInfo ci) + { + if (MobAI.isTracking(this, MobAI.TrackingType.IRON_GOLEM_SPAWNING) && !getEntityWorld().isClient()) + { + ((ServerWorld) getEntityWorld()).spawnParticles(ParticleTypes.BARRIER, x, y+3, z, 1, 0.1, 0.1, 0.1, 0.0); + } + } + + public VillagerEntity_aiMixin(EntityType entityType_1, World world_1) + { + super(entityType_1, world_1); + } +} diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index be10cdfc..2b9b227e 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -679,7 +679,6 @@ public class CarpetExpression this.expr.addLazyFunction("blast_resistance", -1, (c, t, lv) -> genericStateTest(c, "blast_resistance", lv, (s, p, w) -> new NumericValue(s.getBlock().getBlastResistance()))); - // Deprecated this.expr.addLazyFunction("top", -1, (c, t, lv) -> { String type = lv.get(0).evalValue(c).getString().toLowerCase(Locale.ROOT); @@ -693,20 +692,10 @@ public class CarpetExpression case "surface": htype = Heightmap.Type.WORLD_SURFACE; break; default: throw new InternalExpressionException("Unknown heightmap type: "+type); } - int x; - int z; - Value v1 = lv.get(1).evalValue(c); - if (v1 instanceof BlockValue) - { - BlockPos inpos = ((BlockValue)v1).getPos(); - x = inpos.getX(); - z = inpos.getZ(); - } - else - { - x = (int) NumericValue.asNumber(lv.get(1).evalValue(c)).getLong(); - z = (int) NumericValue.asNumber(lv.get(2).evalValue(c)).getLong(); - } + BlockValue.LocatorResult locator = BlockValue.fromParams((CarpetContext)c, lv, 1); + BlockPos pos = locator.block.getPos(); + int x = pos.getX(); + int z = pos.getZ(); Value retval = new NumericValue(((CarpetContext)c).s.getWorld().getChunk(x >> 4, z >> 4).sampleHeightmap(htype, x & 15, z & 15) + 1); return (c_, t_) -> retval; //BlockPos pos = new BlockPos(x,y,z); @@ -965,24 +954,6 @@ public class CarpetExpression return (_c, _t) -> res; }); - /*this.expr.addLazyFunction("trace_block", -1, (c, t, lv) -> { - Value entityValue = lv.get(0).evalValue(c); - if (!(entityValue instanceof EntityValue)) - throw new InternalExpressionException("First argument of trace_block should be an entity"); - Entity e = ((EntityValue) entityValue).getEntity(); - HitResult hitres = Tracer.traceEntityLook(e, 20); - switch (hitres.getType()) - { - case MISS: - return (_c, _t) -> Value.NULL; - case BLOCK: - return (_c, _t) -> new BlockValue(null, e.getEntityWorld(), ((BlockHitResult)hitres).getBlockPos() ); - case ENTITY: - return (_c, _t) -> new EntityValue(((EntityHitResult)hitres).getEntity()); - } - return LazyValue.NULL; - });*/ - this.expr.addLazyFunction("set_biome", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext)c; BlockValue.LocatorResult locator = BlockValue.fromParams(cc, lv, 0); @@ -1736,7 +1707,6 @@ public class CarpetExpression return (c_, t_) -> ListValue.wrap(retlist); }); - this.expr.addLazyFunction("query", -1, (c, t, lv) -> { if (lv.size()<2) { @@ -2516,15 +2486,16 @@ public class CarpetExpression this.expr.addLazyFunction("print", 1, (c, t, lv) -> { ServerCommandSource s = ((CarpetContext)c).s; + Value res = lv.get(0).evalValue(c); if (s.getEntity() instanceof PlayerEntity) { - Messenger.m((PlayerEntity) s.getEntity(), "w "+ lv.get(0).evalValue(c).getString()); + Messenger.m((PlayerEntity) s.getEntity(), "w "+ res.getString()); } else { - Messenger.m(s, "w "+ lv.get(0).evalValue(c).getString()); + Messenger.m(s, "w "+ res.getString()); } - return lv.get(0); // pass through for variables + return (_c, _t) -> res; // pass through for variables }); diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 2b064a22..1f0720f2 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -498,21 +498,9 @@ public class Expression implements Cloneable Value.assertNotNull(v); return lazyfun.apply(c, t, v); } - catch (InternalExpressionException exc) + catch (RuntimeException exc) { - throw new ExpressionException(e, token, exc.getMessage()); - } - catch (ArithmeticException exc) - { - throw new ExpressionException(e, token, "Your math is wrong, "+exc.getMessage()); - } - catch (ExitStatement exit) - { - throw exit; - } - catch (Exception exc) - { - throw new ExpressionException(e, token, "Error while evaluating expression: "+exc.getMessage()); + throw handleCodeException(exc, e, token); } } }); @@ -532,21 +520,9 @@ public class Expression implements Cloneable Value.assertNotNull(v1, v2); return lazyfun.apply(c, type, e, t, v1, v2); } - catch (InternalExpressionException exc) // might not actually throw it + catch (RuntimeException exc) { - throw new ExpressionException(e, t, exc.getMessage()); - } - catch (ArithmeticException exc) - { - throw new ExpressionException(e, t, "Your math is wrong, "+exc.getMessage()); - } - catch (ExitStatement exit) - { - throw exit; - } - catch (Exception exc) - { - throw new ExpressionException(e, t, "Error while evaluating expression: "+exc.getMessage()); + throw handleCodeException(exc, e, t); } } }); @@ -565,26 +541,27 @@ public class Expression implements Cloneable Value.assertNotNull(v1, v2); return lazyfun.apply(c, t, v1, v2); } - catch (InternalExpressionException exc) + catch (RuntimeException exc) { - throw new ExpressionException(e, token, exc.getMessage()); - } - catch (ArithmeticException exc) - { - throw new ExpressionException(e, token, "Your math is wrong, "+exc.getMessage()); - } - catch (ExitStatement exit) - { - throw exit; - } - catch (Exception exc) - { - throw new ExpressionException(e, token, "Error while evaluating expression: "+exc.getMessage()); + throw handleCodeException(exc, e, token); } } }); } + private RuntimeException handleCodeException(RuntimeException exc, Expression e, Tokenizer.Token token) + { + if (exc instanceof ExitStatement) + return exc; + if (exc instanceof InternalExpressionException) + return new ExpressionException(e, token, exc.getMessage()); + if (exc instanceof ArithmeticException) + return new ExpressionException(e, token, "Your math is wrong, "+exc.getMessage()); + if (exc instanceof ExpressionException) + return exc; + return new ExpressionException(e, token, "Error while evaluating expression: "+exc.getMessage()); + } + private void addUnaryOperator(String surface, boolean leftAssoc, Function fun) { operators.put(surface+"u", new AbstractUnaryOperator(precedence.get("unary+-!"), leftAssoc) @@ -679,22 +656,10 @@ public class Expression implements Cloneable { return fun.apply(c, i, lazyParams); } - catch (InternalExpressionException exc) + catch (RuntimeException exc) { - throw new ExpressionException(e, t, exc.getMessage()); + throw handleCodeException(exc, e, t); } - catch (ArithmeticException exc) - { - throw new ExpressionException(e, t, "Your math is wrong, "+exc.getMessage()); - } - catch (ExitStatement exit) - { - throw exit; - } - //catch (Exception exc) - //{ - // throw new ExpressionException(e, t, "Error while evaluating expression: "+exc.getMessage()); - //} } }); } @@ -770,7 +735,7 @@ public class Expression implements Cloneable { throw new ExpressionException(function_context, t, "Your math is wrong, "+exc.getMessage()); } - catch (ExitStatement exit) + catch (ExitStatement | ExpressionException exit) { throw exit; } @@ -1060,7 +1025,7 @@ public class Expression implements Cloneable Value ret = lv.get(lv.size() - 1).evalValue(c); return (cc, tt) -> ret; } - return (cc, tt) -> Value.ZERO; + return (cc, tt) -> Value.NULL; }); } @@ -1892,8 +1857,6 @@ public class Expression implements Cloneable return LazyListValue.range(from, to, step); }); - addUnaryFunction("is_list", value -> (value instanceof ListValue)? Value.TRUE : Value.FALSE); - addBinaryFunction("get", (v1, v2) -> v1.getElementAt(v2)); //Deprecated, use "get" instead @@ -2512,6 +2475,8 @@ public class Expression implements Cloneable } }); + addUnaryFunction("type", v -> new StringValue(v.getTypeString())); + addUnaryFunction("length", v -> new NumericValue(v.length())); addLazyFunction("rand", 1, (c, t, lv) -> { Value argument = lv.get(0).evalValue(c); diff --git a/src/main/java/carpet/script/ScriptHost.java b/src/main/java/carpet/script/ScriptHost.java index b032bae4..a73f2cb0 100644 --- a/src/main/java/carpet/script/ScriptHost.java +++ b/src/main/java/carpet/script/ScriptHost.java @@ -73,12 +73,10 @@ public class ScriptHost try { ServerPlayerEntity player = source.getPlayer(); - CarpetSettings.LOG.error("Retrieving "+player.getName().getString()+" host for "+getName()); return retrieveForExecution(player.getName().getString()); } catch (CommandSyntaxException e) { - CarpetSettings.LOG.error("Retrieving global host for "+getName()); return retrieveForExecution((String)null); } } diff --git a/src/main/java/carpet/script/value/BlockValue.java b/src/main/java/carpet/script/value/BlockValue.java index 460abe00..11073e6b 100644 --- a/src/main/java/carpet/script/value/BlockValue.java +++ b/src/main/java/carpet/script/value/BlockValue.java @@ -241,6 +241,12 @@ public class BlockValue extends Value return this != NULL && !getBlockState().isAir(); } + @Override + public String getTypeString() + { + return "block"; + } + @Override public Value clone() { diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java index 037850ba..8ba290a6 100644 --- a/src/main/java/carpet/script/value/EntityValue.java +++ b/src/main/java/carpet/script/value/EntityValue.java @@ -1,6 +1,7 @@ package carpet.script.value; import carpet.fakes.MobEntityInterface; +import carpet.helpers.Tracer; import carpet.script.exception.InternalExpressionException; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -30,6 +31,9 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.text.LiteralText; import net.minecraft.util.Identifier; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; @@ -124,6 +128,12 @@ public class EntityValue extends Value return this.get(what, null); } + @Override + public String getTypeString() + { + return "entity"; + } + public static Pair, Predicate> getPredicate(String who) { Pair, Predicate> res = entityPredicates.get(who); @@ -310,20 +320,65 @@ public class EntityValue extends Value return new StringValue(Direction.getEntityFacingOrder(e)[index].asString()); }); + put("trace", (e, a) -> + { + float reach = 4.5f; + boolean entities = true; + boolean liquids = false; + + if (a!=null) + { + if (!(a instanceof ListValue)) + { + reach = (float) NumericValue.asNumber(a).getDouble(); + } + else + { + List args = ((ListValue) a).getItems(); + if (args.size()==0) + throw new InternalExpressionException("trace needs more arguments"); + reach = (float) NumericValue.asNumber(args.get(0)).getDouble(); + if (args.size() > 1) + { + entities = false; + for (int i = 1; i < args.size(); i++) + { + String what = args.get(i).getString(); + if (what.equalsIgnoreCase("entities")) + entities = true; + else if (what.equalsIgnoreCase("blocks")) {} + else if (what.equalsIgnoreCase("liquids")) + liquids = true; + else throw new InternalExpressionException("Incorrect tracing: "+what); + } + } + } + } + else if (e instanceof ServerPlayerEntity && ((ServerPlayerEntity) e).interactionManager.isCreative()) + { + reach = 5.0f; + } + + HitResult hitres; + if (entities) + hitres = Tracer.rayTrace(e, 1, reach, liquids); + else + hitres = Tracer.rayTraceBlocks(e, 1, reach, liquids); + + switch (hitres.getType()) + { + case MISS: return Value.NULL; + case BLOCK: return new BlockValue(null, e.getEntityWorld(), ((BlockHitResult)hitres).getBlockPos() ); + case ENTITY: return new EntityValue(((EntityHitResult)hitres).getEntity()); + } + return Value.NULL; + }); + put("nbt",(e, a) -> { CompoundTag nbttagcompound = e.toTag((new CompoundTag())); if (a==null) return new NBTSerializableValue(nbttagcompound);//StringValue(nbttagcompound.toString()); - NbtPathArgumentType.NbtPath path; - try - { - path = NbtPathArgumentType.nbtPath().method_9362(new StringReader(a.getString())); - } - catch (CommandSyntaxException exc) - { - throw new InternalExpressionException("Incorrect path: "+a.getString()); - } - String res = null; + NbtPathArgumentType.NbtPath path = NBTSerializableValue.cachePath(a.getString()); try { List tags = path.get(nbttagcompound); @@ -331,7 +386,7 @@ public class EntityValue extends Value return Value.NULL; if (tags.size()==1) return NBTSerializableValue.decodeTag(tags.get(0)); - return ListValue.wrap(tags.stream().map(t -> NBTSerializableValue.decodeTag(t)).collect(Collectors.toList())); + return ListValue.wrap(tags.stream().map(NBTSerializableValue::decodeTag).collect(Collectors.toList())); } catch (CommandSyntaxException ignored) { } return Value.NULL; @@ -504,9 +559,13 @@ public class EntityValue extends Value }); put("custom_name", (e, v) -> { - String name = v.getString(); - if (name.isEmpty()) + if (v instanceof NullValue) + { + e.setCustomNameVisible(false); e.setCustomName(null); + return; + } + e.setCustomNameVisible(true); e.setCustomName(new LiteralText(v.getString())); }); put("dismount", (e, v) -> e.stopRiding() ); diff --git a/src/main/java/carpet/script/value/FunctionSignatureValue.java b/src/main/java/carpet/script/value/FunctionSignatureValue.java index 2fefaf05..b54274ab 100644 --- a/src/main/java/carpet/script/value/FunctionSignatureValue.java +++ b/src/main/java/carpet/script/value/FunctionSignatureValue.java @@ -1,7 +1,7 @@ package carpet.script.value; import carpet.script.exception.ExpressionException; -import carpet.script.value.Value; +import carpet.script.exception.InternalExpressionException; import java.util.List; @@ -23,6 +23,12 @@ public class FunctionSignatureValue extends Value throw new ExpressionException("Function "+identifier+" is not defined yet"); } + @Override + public String getTypeString() + { + throw new InternalExpressionException("How did you get here? Cannot get type of an internal struct."); + } + @Override public Value clone() { diff --git a/src/main/java/carpet/script/value/GlobalValue.java b/src/main/java/carpet/script/value/GlobalValue.java index ae51b0e3..fb2f3f71 100644 --- a/src/main/java/carpet/script/value/GlobalValue.java +++ b/src/main/java/carpet/script/value/GlobalValue.java @@ -1,6 +1,6 @@ package carpet.script.value; -import carpet.script.value.Value; +import carpet.script.exception.InternalExpressionException; public class GlobalValue extends Value { @@ -21,4 +21,10 @@ public class GlobalValue extends Value { return false; } + + @Override + public String getTypeString() + { + throw new InternalExpressionException("How did you get here? Cannot get type of an internal struct."); + } } diff --git a/src/main/java/carpet/script/value/LazyListValue.java b/src/main/java/carpet/script/value/LazyListValue.java index 8bf16cc2..accf40a5 100644 --- a/src/main/java/carpet/script/value/LazyListValue.java +++ b/src/main/java/carpet/script/value/LazyListValue.java @@ -111,5 +111,10 @@ public abstract class LazyListValue extends ListValue implements Iterator { throw new InternalExpressionException("get element can only be obtained for regular lists"); } + @Override + public String getTypeString() + { + return "iterator"; + } } diff --git a/src/main/java/carpet/script/value/ListValue.java b/src/main/java/carpet/script/value/ListValue.java index ab7a47f6..f7ac3662 100644 --- a/src/main/java/carpet/script/value/ListValue.java +++ b/src/main/java/carpet/script/value/ListValue.java @@ -326,6 +326,11 @@ public class ListValue extends Value index = index % numitems; return items.get((int)index); } + @Override + public String getTypeString() + { + return "list"; + } diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java index 0d4a6b9a..f3e822c5 100644 --- a/src/main/java/carpet/script/value/NBTSerializableValue.java +++ b/src/main/java/carpet/script/value/NBTSerializableValue.java @@ -26,8 +26,6 @@ import java.util.Map; import java.util.function.Supplier; import java.util.stream.Collectors; -import static java.lang.Math.abs; - public class NBTSerializableValue extends Value { private String nbtString = null; @@ -224,31 +222,38 @@ public class NBTSerializableValue extends Value } } - @Override - public Value getElementAt(Value value) + private static Map pathCache = new HashMap<>(); + public static NbtPathArgumentType.NbtPath cachePath(String arg) { - String pathString = value.getString(); - - //return Value.NULL; - - NbtPathArgumentType.NbtPath path; + NbtPathArgumentType.NbtPath res = pathCache.get(arg); + if (res != null) + return res; try { - path = NbtPathArgumentType.nbtPath().method_9362(new StringReader(pathString)); + res = NbtPathArgumentType.nbtPath().method_9362(new StringReader(arg)); } catch (CommandSyntaxException exc) { - throw new InternalExpressionException("Incorrect nbt path: "+pathString); + throw new InternalExpressionException("Incorrect nbt path: "+arg); } - String res = null; + if (pathCache.size() > 1024) + pathCache.clear(); + pathCache.put(arg, res); + return res; + } + + @Override + public Value getElementAt(Value value) + { + NbtPathArgumentType.NbtPath path = cachePath(value.getString()); try { List tags = path.get(getTag()); if (tags.size()==0) return Value.NULL; if (tags.size()==1) - return new NBTSerializableValue(tags.get(0)); - return ListValue.wrap(tags.stream().map(NBTSerializableValue::new).collect(Collectors.toList())); + return NBTSerializableValue.decodeTag(tags.get(0)); + return ListValue.wrap(tags.stream().map(NBTSerializableValue::decodeTag).collect(Collectors.toList())); } catch (CommandSyntaxException ignored) { } return Value.NULL; @@ -259,4 +264,10 @@ public class NBTSerializableValue extends Value index = index % numitems; return items.get((int)index); */ } + + @Override + public String getTypeString() + { + return "nbt"; + } } diff --git a/src/main/java/carpet/script/value/NullValue.java b/src/main/java/carpet/script/value/NullValue.java index f7d9858b..a749a40b 100644 --- a/src/main/java/carpet/script/value/NullValue.java +++ b/src/main/java/carpet/script/value/NullValue.java @@ -38,4 +38,10 @@ public class NullValue extends NumericValue // TODO check nonsingleton code { return o instanceof NullValue ? 0 : -1; } + + @Override + public String getTypeString() + { + return "null"; + } } diff --git a/src/main/java/carpet/script/value/NumericValue.java b/src/main/java/carpet/script/value/NumericValue.java index ec7bc9b2..ddc3cbb8 100644 --- a/src/main/java/carpet/script/value/NumericValue.java +++ b/src/main/java/carpet/script/value/NumericValue.java @@ -167,4 +167,10 @@ public class NumericValue extends Value return getLong(); } + @Override + public String getTypeString() + { + return "number"; + } + } diff --git a/src/main/java/carpet/script/value/StringValue.java b/src/main/java/carpet/script/value/StringValue.java index 650d6211..3db05b75 100644 --- a/src/main/java/carpet/script/value/StringValue.java +++ b/src/main/java/carpet/script/value/StringValue.java @@ -24,4 +24,10 @@ public class StringValue extends Value { this.str = str; } + + @Override + public String getTypeString() + { + return "number"; + } } diff --git a/src/main/java/carpet/script/value/Value.java b/src/main/java/carpet/script/value/Value.java index 454b5871..35c94827 100644 --- a/src/main/java/carpet/script/value/Value.java +++ b/src/main/java/carpet/script/value/Value.java @@ -177,4 +177,6 @@ public abstract class Value implements Comparable, Cloneable { throw new InternalExpressionException("get element can only be obtained for lists and nbt values"); } + + public abstract String getTypeString(); } diff --git a/src/main/java/carpet/settings/CarpetSettings.java b/src/main/java/carpet/settings/CarpetSettings.java index 6b2138be..842498e3 100644 --- a/src/main/java/carpet/settings/CarpetSettings.java +++ b/src/main/java/carpet/settings/CarpetSettings.java @@ -211,6 +211,9 @@ public class CarpetSettings @Rule(desc = "Enables /player command to control/spawn players", category = COMMAND) public static boolean commandPlayer = true; + @Rule(desc = "Allows to track mobs AI via /track command", category = COMMAND) + public static boolean commandTrackAI = true; + @Rule(desc = "Placing carpets may issue carpet commands for non-op players", category = SURVIVAL) public static boolean carpets = false; diff --git a/src/main/java/carpet/utils/MobAI.java b/src/main/java/carpet/utils/MobAI.java new file mode 100644 index 00000000..76f94401 --- /dev/null +++ b/src/main/java/carpet/utils/MobAI.java @@ -0,0 +1,93 @@ +package carpet.utils; + +import carpet.CarpetServer; +import com.google.common.collect.Sets; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.registry.Registry; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class MobAI +{ + private static Map> aiTrackers = new HashMap<>(); + + public static void resetTrackers() + { + aiTrackers.clear(); + } + + public static boolean isTracking(Entity e, TrackingType type) + { + Set currentTrackers = aiTrackers.get(e.getType()); + if (currentTrackers == null) + return false; + return currentTrackers.contains(type); + } + + public static void clearTracking(EntityType etype) + { + aiTrackers.remove(etype); + for(ServerWorld world : CarpetServer.minecraft_server.getWorlds() ) + { + for (Entity e: world.getEntities(etype, Entity::hasCustomName)) + { + e.setCustomNameVisible(false); + e.setCustomName(null); + } + } + } + + public static void startTracking(EntityType e, TrackingType type) + { + aiTrackers.putIfAbsent(e,Sets.newHashSet()); + aiTrackers.get(e).add(type); + } + + public static List availbleTypes() + { + Set types = new HashSet<>(); + for (TrackingType type: TrackingType.values()) + { + types.addAll(type.types); + } + return types.stream().map(t -> Registry.ENTITY_TYPE.getId(t).getPath()).collect(Collectors.toList()); + } + + public static List availableFor(EntityType entityType) + { + Set availableOptions = new HashSet<>(); + for (TrackingType type: TrackingType.values()) + for (EntityType etype: type.types) + if (etype == entityType) + availableOptions.add(type); + return availableOptions.stream().map(t -> t.name).collect(Collectors.toList()); + } + + public enum TrackingType + { + IRON_GOLEM_SPAWNING("iron_golem_spawning", Sets.newHashSet(EntityType.VILLAGER)); + public Set types; + public String name; + TrackingType(String name, Set applicableTypes) + { + this.name = name; + types = applicableTypes; + } + + public static TrackingType byName(String aspect) + { + for (TrackingType type: values()) + if (type.name.equalsIgnoreCase(aspect)) + return type; + return null; + } + } + +} diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index 2b96c42e..e137da04 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -27,6 +27,8 @@ "ServerWorld_unloadedEntityMixin", "MobEntity_leashMixin", + "VillagerEntity_aiMixin", + "ServerWorld_fakePlayersMixin", "ServerPlayNetworkHandler_coreMixin",