diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 2c847a57..9df9d7c3 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -8,6 +8,7 @@ import carpet.script.api.Entities; import carpet.script.api.Inventories; import carpet.script.api.Monitoring; import carpet.script.api.Scoreboards; +import carpet.script.api.Threading; import carpet.script.api.WorldAccess; import carpet.script.bundled.Module; import carpet.script.exception.CarpetExpressionException; @@ -42,6 +43,7 @@ public class CarpetExpression Inventories.apply(this.expr); BlockIterators.apply(this.expr); Auxiliary.apply(this.expr); + Threading.apply(this.expr); Scoreboards.apply(this.expr); Apps.apply(this.expr); Monitoring.apply(this.expr); diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 93cc3491..9964deb1 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -26,6 +26,7 @@ import carpet.script.language.Functions; import carpet.script.language.Loops; import carpet.script.language.Operators; import carpet.script.language.Sys; +import carpet.script.language.Threading; import carpet.script.value.FunctionValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; @@ -407,6 +408,7 @@ public class Expression Functions.apply(this); Arithmetic.apply(this); Sys.apply(this); + Threading.apply(this); Loops.apply(this); DataStructures.apply(this); } diff --git a/src/main/java/carpet/script/api/Auxiliary.java b/src/main/java/carpet/script/api/Auxiliary.java index e4e62dc9..48925ca0 100644 --- a/src/main/java/carpet/script/api/Auxiliary.java +++ b/src/main/java/carpet/script/api/Auxiliary.java @@ -15,9 +15,9 @@ import carpet.script.argument.BlockArgument; import carpet.script.argument.FunctionArgument; import carpet.script.argument.Vector3Argument; import carpet.script.exception.ExitStatement; -import carpet.script.exception.ExpressionException; import carpet.script.exception.InternalExpressionException; import carpet.script.utils.ShapeDispatcher; +import carpet.script.utils.WorldTools; import carpet.script.value.BlockValue; import carpet.script.value.EntityValue; import carpet.script.value.FormattedTextValue; @@ -26,7 +26,6 @@ import carpet.script.value.NBTSerializableValue; import carpet.script.value.NullValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; -import carpet.script.value.ThreadValue; import carpet.script.value.Value; import carpet.script.value.ValueConversions; import carpet.utils.Messenger; @@ -66,7 +65,6 @@ import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.concurrent.CompletionException; import java.util.stream.Collectors; import static java.lang.Math.max; @@ -459,60 +457,6 @@ public class Auxiliary { return (cc, tt) -> ret; }); - //"overidden" native call to cancel if on main thread - expression.addLazyFunction("task_join", 1, (c, t, lv) -> { - if (((CarpetContext)c).s.getMinecraftServer().isOnThread()) - throw new InternalExpressionException("'task_join' cannot be called from main thread to avoid deadlocks"); - Value v = lv.get(0).evalValue(c); - if (!(v instanceof ThreadValue)) - throw new InternalExpressionException("'task_join' could only be used with a task value"); - Value ret = ((ThreadValue) v).join(); - return (_c, _t) -> ret; - }); - - expression.addLazyFunctionWithDelegation("task_dock", 1, (c, t, expr, tok, lv) -> { - CarpetContext cc = (CarpetContext)c; - MinecraftServer server = cc.s.getMinecraftServer(); - if (server.isOnThread()) return lv.get(0); // pass through for on thread tasks - Value[] result = new Value[]{Value.NULL}; - RuntimeException[] internal = new RuntimeException[]{null}; - try - { - ((CarpetContext) c).s.getMinecraftServer().submitAndJoin(() -> - { - try - { - result[0] = lv.get(0).evalValue(c, t); - } - catch (ExpressionException exc) - { - internal[0] = exc; - } - catch (InternalExpressionException exc) - { - internal[0] = new ExpressionException(c, expr, tok, exc.getMessage(), exc.stack); - } - - catch (ArithmeticException exc) - { - internal[0] = new ExpressionException(c, expr, tok, "Your math is wrong, "+exc.getMessage()); - } - }); - } - catch (CompletionException exc) - { - throw new InternalExpressionException("Error while executing docked task section, internal stack trace is gone"); - } - if (internal[0] != null) - { - throw internal[0]; - } - Value ret = result[0]; // preventing from lazy evaluating of the result in case a future completes later - return (_c, _t) -> ret; - // pass through placeholder - // implmenetation should dock the task on the main thread. - }); - expression.addLazyFunction("run", 1, (c, t, lv) -> { BlockPos target = ((CarpetContext)c).origin; Vec3d posf = new Vec3d((double)target.getX()+0.5D,(double)target.getY(),(double)target.getZ()+0.5D); @@ -616,7 +560,7 @@ public class Auxiliary { BlockPos pos = locator.block.getPos(); ServerWorld world = cc.s.getWorld(); ((ThreadedAnvilChunkStorageInterface) world.getChunkManager().threadedAnvilChunkStorage).relightChunk(new ChunkPos(pos)); - WorldAccess.forceChunkUpdate(pos, world); + WorldTools.forceChunkUpdate(pos, world); return LazyValue.TRUE; }); @@ -708,7 +652,7 @@ public class Auxiliary { if (res == null) return; if (what.equalsIgnoreCase("boulder")) // there might be more of those - WorldAccess.forceChunkUpdate(locator.block.getPos(), ((CarpetContext) c).s.getWorld()); + WorldTools.forceChunkUpdate(locator.block.getPos(), ((CarpetContext) c).s.getWorld()); result[0] = new NumericValue(res); }); Value ret = result[0]; // preventing from lazy evaluating of the result in case a future completes later diff --git a/src/main/java/carpet/script/api/Entities.java b/src/main/java/carpet/script/api/Entities.java index 252a4946..72011a6f 100644 --- a/src/main/java/carpet/script/api/Entities.java +++ b/src/main/java/carpet/script/api/Entities.java @@ -39,7 +39,8 @@ import java.util.stream.Collectors; public class Entities { public static void apply(Expression expression) { - expression.addLazyFunction("player", -1, (c, t, lv) -> { + expression.addLazyFunction("player", -1, (c, t, lv) -> + { if (lv.size() ==0) { @@ -106,7 +107,8 @@ public class Entities { return (cc, tt) -> finalVar; }); - expression.addLazyFunction("spawn", -1, (c, t, lv) -> { + expression.addLazyFunction("spawn", -1, (c, t, lv) -> + { CarpetContext cc = (CarpetContext)c; if (lv.size() < 2) throw new InternalExpressionException("'spawn' function takes mob name, and position to spawn"); @@ -176,7 +178,8 @@ public class Entities { return (cc, tt) -> new EntityValue(e); }); - expression.addLazyFunction("entity_list", 1, (c, t, lv) -> { + expression.addLazyFunction("entity_list", 1, (c, t, lv) -> + { String who = lv.get(0).evalValue(c).getString(); Pair, Predicate> pair = EntityValue.getPredicate(who); if (pair == null) @@ -188,7 +191,8 @@ public class Entities { return (_c, _t ) -> retval; }); - expression.addLazyFunction("entity_area", 7, (c, t, lv) -> { + expression.addLazyFunction("entity_area", 7, (c, t, lv) -> + { Vec3d center = new Vec3d( NumericValue.asNumber(lv.get(1).evalValue(c)).getDouble(), NumericValue.asNumber(lv.get(2).evalValue(c)).getDouble(), @@ -221,7 +225,8 @@ public class Entities { return (c_, t_) -> ListValue.wrap(retlist); }); - expression.addLazyFunction("query", -1, (c, t, lv) -> { + expression.addLazyFunction("query", -1, (c, t, lv) -> + { if (lv.size()<2) { throw new InternalExpressionException("'query' takes entity as a first argument, and queried feature as a second"); @@ -241,7 +246,8 @@ public class Entities { }); // or update - expression.addLazyFunction("modify", -1, (c, t, lv) -> { + expression.addLazyFunction("modify", -1, (c, t, lv) -> + { if (lv.size()<2) { throw new InternalExpressionException("'modify' takes entity as a first argument, and queried feature as a second"); diff --git a/src/main/java/carpet/script/api/Inventories.java b/src/main/java/carpet/script/api/Inventories.java index 37134c22..4615c742 100644 --- a/src/main/java/carpet/script/api/Inventories.java +++ b/src/main/java/carpet/script/api/Inventories.java @@ -309,7 +309,8 @@ public class Inventories { }); //inventory_remove(, , ) -> bool - expression.addLazyFunction("inventory_remove", -1, (c, t, lv) -> { + expression.addLazyFunction("inventory_remove", -1, (c, t, lv) -> + { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); if (inventoryLocator == null) diff --git a/src/main/java/carpet/script/api/Scoreboards.java b/src/main/java/carpet/script/api/Scoreboards.java index 4508daaf..748d1124 100644 --- a/src/main/java/carpet/script/api/Scoreboards.java +++ b/src/main/java/carpet/script/api/Scoreboards.java @@ -74,7 +74,8 @@ public class Scoreboards { return (_c, _t) -> retval; }); - expression.addLazyFunction("scoreboard_remove", -1, (c, t, lv)-> { + expression.addLazyFunction("scoreboard_remove", -1, (c, t, lv)-> + { if (lv.size()==0) throw new InternalExpressionException("'scoreboard_remove' requires at least one parameter"); CarpetContext cc = (CarpetContext)c; Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); @@ -98,7 +99,8 @@ public class Scoreboards { // objective_add('lvl','level') // objective_add('counter') - expression.addLazyFunction("scoreboard_add", -1, (c, t, lv)-> { + expression.addLazyFunction("scoreboard_add", -1, (c, t, lv)-> + { CarpetContext cc = (CarpetContext)c; Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); if (lv.size() == 0 || lv.size()>2) throw new InternalExpressionException("'scoreboard_add' should have one or two parameters"); diff --git a/src/main/java/carpet/script/api/Threading.java b/src/main/java/carpet/script/api/Threading.java new file mode 100644 index 00000000..c17a3ad0 --- /dev/null +++ b/src/main/java/carpet/script/api/Threading.java @@ -0,0 +1,71 @@ +package carpet.script.api; + +import carpet.script.CarpetContext; +import carpet.script.Expression; +import carpet.script.exception.ExpressionException; +import carpet.script.exception.InternalExpressionException; +import carpet.script.value.ThreadValue; +import carpet.script.value.Value; +import net.minecraft.server.MinecraftServer; + +import java.util.concurrent.CompletionException; + +public class Threading +{ + public static void apply(Expression expression) + { + //"overidden" native call to cancel if on main thread + expression.addLazyFunction("task_join", 1, (c, t, lv) -> { + if (((CarpetContext)c).s.getMinecraftServer().isOnThread()) + throw new InternalExpressionException("'task_join' cannot be called from main thread to avoid deadlocks"); + Value v = lv.get(0).evalValue(c); + if (!(v instanceof ThreadValue)) + throw new InternalExpressionException("'task_join' could only be used with a task value"); + Value ret = ((ThreadValue) v).join(); + return (_c, _t) -> ret; + }); + + expression.addLazyFunctionWithDelegation("task_dock", 1, (c, t, expr, tok, lv) -> { + CarpetContext cc = (CarpetContext)c; + MinecraftServer server = cc.s.getMinecraftServer(); + if (server.isOnThread()) return lv.get(0); // pass through for on thread tasks + Value[] result = new Value[]{Value.NULL}; + RuntimeException[] internal = new RuntimeException[]{null}; + try + { + ((CarpetContext) c).s.getMinecraftServer().submitAndJoin(() -> + { + try + { + result[0] = lv.get(0).evalValue(c, t); + } + catch (ExpressionException exc) + { + internal[0] = exc; + } + catch (InternalExpressionException exc) + { + internal[0] = new ExpressionException(c, expr, tok, exc.getMessage(), exc.stack); + } + + catch (ArithmeticException exc) + { + internal[0] = new ExpressionException(c, expr, tok, "Your math is wrong, "+exc.getMessage()); + } + }); + } + catch (CompletionException exc) + { + throw new InternalExpressionException("Error while executing docked task section, internal stack trace is gone"); + } + if (internal[0] != null) + { + throw internal[0]; + } + Value ret = result[0]; // preventing from lazy evaluating of the result in case a future completes later + return (_c, _t) -> ret; + // pass through placeholder + // implmenetation should dock the task on the main thread. + }); + } +} diff --git a/src/main/java/carpet/script/api/WorldAccess.java b/src/main/java/carpet/script/api/WorldAccess.java index 1ab0a7ff..c149ae67 100644 --- a/src/main/java/carpet/script/api/WorldAccess.java +++ b/src/main/java/carpet/script/api/WorldAccess.java @@ -28,6 +28,7 @@ import carpet.script.value.NullValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; import carpet.script.value.Value; +import carpet.script.value.ValueConversions; import carpet.utils.BlockInfo; import com.mojang.brigadier.exceptions.CommandSyntaxException; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -56,7 +57,6 @@ import net.minecraft.item.SwordItem; import net.minecraft.item.TridentItem; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; -import net.minecraft.network.packet.s2c.play.ChunkDataS2CPacket; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ChunkTicket; import net.minecraft.server.world.ChunkTicketType; @@ -65,7 +65,6 @@ import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; import net.minecraft.state.StateManager; import net.minecraft.state.property.Property; -import net.minecraft.structure.StructurePiece; import net.minecraft.structure.StructureStart; import net.minecraft.util.ActionResult; import net.minecraft.util.Clearable; @@ -118,23 +117,6 @@ public class WorldAccess { // dummy entity for dummy requirements in the loot tables (see snowball) private static FallingBlockEntity DUMMY_ENTITY = new FallingBlockEntity(EntityType.FALLING_BLOCK, null); - public static void forceChunkUpdate(BlockPos pos, ServerWorld world) - { - WorldChunk worldChunk = world.getChunkManager().getWorldChunk(pos.getX()>>4, pos.getZ()>>4, false); - if (worldChunk != null) - { - int vd = world.getServer().getPlayerManager().getViewDistance() * 16; - int vvd = vd * vd; - List nearbyPlayers = world.getPlayers(p -> pos.getSquaredDistance(p.getX(), pos.getY(), p.getZ(), true) < vvd); - if (!nearbyPlayers.isEmpty()) - { - ChunkDataS2CPacket packet = new ChunkDataS2CPacket(worldChunk, 65535); - ChunkPos chpos = new ChunkPos(pos); - nearbyPlayers.forEach(p -> p.networkHandler.sendPacket(packet)); - } - } - } - private static LazyValue booleanStateTest( Context c, String name, @@ -270,30 +252,6 @@ public class WorldAccess { } } - private static Value structureToValue(StructureStart structure) - { - if (structure == null || structure == StructureStart.DEFAULT) return Value.NULL; - List pieces = new ArrayList<>(); - for (StructurePiece piece : structure.getChildren()) - { - BlockBox box = piece.getBoundingBox(); - pieces.add(ListValue.of( - new StringValue( NBTSerializableValue.nameFromRegistryId(Registry.STRUCTURE_PIECE.getId(piece.getType()))), - (piece.getFacing()== null)?Value.NULL: new StringValue(piece.getFacing().getName()), - ListValue.fromTriple(box.minX, box.minY, box.minZ), - ListValue.fromTriple(box.maxX, box.maxY, box.maxZ) - )); - }; - BlockBox boundingBox = structure.getBoundingBox(); - Map ret = new HashMap<>(); - ret.put(new StringValue("box"), ListValue.of( - ListValue.fromTriple(boundingBox.minX, boundingBox.minY, boundingBox.minZ), - ListValue.fromTriple(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ) - )); - ret.put(new StringValue("pieces"), ListValue.wrap(pieces)); - return MapValue.wrap(ret); - } - private static void BooYah(ChunkGenerator generator) { synchronized (generator) @@ -1058,7 +1016,7 @@ public class WorldAccess { BlockPos pos = locator.block.getPos(); Chunk chunk = world.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.BIOMES); ((BiomeArrayInterface)chunk.getBiomeArray()).setBiomeAtIndex(pos, world, biome); - if (doImmediateUpdate) forceChunkUpdate(pos, world); + if (doImmediateUpdate) WorldTools.forceChunkUpdate(pos, world); return LazyValue.TRUE; }); @@ -1066,7 +1024,7 @@ public class WorldAccess { CarpetContext cc = (CarpetContext)c; BlockPos pos = BlockArgument.findIn(cc, lv, 0).block.getPos(); ServerWorld world = cc.s.getWorld(); - cc.s.getMinecraftServer().submitAndJoin( () -> forceChunkUpdate(pos, world)); + cc.s.getMinecraftServer().submitAndJoin( () -> WorldTools.forceChunkUpdate(pos, world)); return LazyValue.TRUE; }); @@ -1130,7 +1088,7 @@ public class WorldAccess { StructureStart start = FeatureGenerator.shouldStructureStartAt(world, pos, structure, needSize); if (start == null) return LazyValue.NULL; if (!needSize) return LazyValue.TRUE; - Value ret = structureToValue(start); + Value ret = ValueConversions.fromStructure(start); return (_c, _t) -> ret; } Map ret = new HashMap<>(); @@ -1140,7 +1098,7 @@ public class WorldAccess { if (start == null) continue; Value key = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.STRUCTURE_FEATURE.getId(str))); - ret.put(key, (!needSize)?Value.NULL:structureToValue(start)); + ret.put(key, (!needSize)?Value.NULL: ValueConversions.fromStructure(start)); } Value retMap = MapValue.wrap(ret); return (_c, _t) -> retMap; @@ -1172,7 +1130,7 @@ public class WorldAccess { } String structureName = lv.get(locator.offset).evalValue(c).getString().toLowerCase(Locale.ROOT); StructureStart start = structures.get(Registry.STRUCTURE_FEATURE.get(new Identifier(structureName))); - Value ret = structureToValue(start); + Value ret = ValueConversions.fromStructure(start); return (_c, _t) -> ret; }); @@ -1321,7 +1279,7 @@ public class WorldAccess { { if (world.getChunk(chpos.x, chpos.z, ChunkStatus.FULL, false) != null) { - forceChunkUpdate(chpos.getStartPos(), world); + WorldTools.forceChunkUpdate(chpos.getStartPos(), world); } } result[0] = MapValue.wrap(report.entrySet().stream().collect(Collectors.toMap( diff --git a/src/main/java/carpet/script/language/Arithmetic.java b/src/main/java/carpet/script/language/Arithmetic.java index 750b1ae7..cb8d5281 100644 --- a/src/main/java/carpet/script/language/Arithmetic.java +++ b/src/main/java/carpet/script/language/Arithmetic.java @@ -14,103 +14,102 @@ public class Arithmetic { "2.71828182845904523536028747135266249775724709369995957496696762772407663"); public static void apply(Expression expression) + { + expression.addLazyFunction("not", 1, (c, t, lv) -> lv.get(0).evalValue(c, Context.BOOLEAN).getBoolean() ? ((cc, tt) -> Value.FALSE) : ((cc, tt) -> Value.TRUE)); + expression.addUnaryFunction("fact", (v) -> + { + long number = NumericValue.asNumber(v).getLong(); + long factorial = 1; + for (int i = 1; i <= number; i++) { - expression.addLazyFunction("not", 1, (c, t, lv) -> lv.get(0).evalValue(c, Context.BOOLEAN).getBoolean() ? ((cc, tt) -> Value.FALSE) : ((cc, tt) -> Value.TRUE)); - - expression.addUnaryFunction("fact", (v) -> - { - long number = NumericValue.asNumber(v).getLong(); - long factorial = 1; - for (int i = 1; i <= number; i++) - { - factorial = factorial * i; - } - return new NumericValue(factorial); - }); - expression.addMathematicalUnaryFunction("sin", (d) -> Math.sin(Math.toRadians(d))); - expression.addMathematicalUnaryFunction("cos", (d) -> Math.cos(Math.toRadians(d))); - expression.addMathematicalUnaryFunction("tan", (d) -> Math.tan(Math.toRadians(d))); - expression.addMathematicalUnaryFunction("asin", (d) -> Math.toDegrees(Math.asin(d))); - expression.addMathematicalUnaryFunction("acos", (d) -> Math.toDegrees(Math.acos(d))); - expression.addMathematicalUnaryFunction("atan", (d) -> Math.toDegrees(Math.atan(d))); - expression.addMathematicalBinaryFunction("atan2", (d, d2) -> Math.toDegrees(Math.atan2(d, d2)) ); - expression.addMathematicalUnaryFunction("sinh", Math::sinh ); - expression.addMathematicalUnaryFunction("cosh", Math::cosh ); - expression.addMathematicalUnaryFunction("tanh", Math::tanh ); - expression.addMathematicalUnaryFunction("sec", (d) -> 1.0 / Math.cos(Math.toRadians(d)) ); // Formula: sec(x) = 1 / cos(x) - expression.addMathematicalUnaryFunction("csc", (d) -> 1.0 / Math.sin(Math.toRadians(d)) ); // Formula: csc(x) = 1 / sin(x) - expression.addMathematicalUnaryFunction("sech", (d) -> 1.0 / Math.cosh(d) ); // Formula: sech(x) = 1 / cosh(x) - expression.addMathematicalUnaryFunction("csch", (d) -> 1.0 / Math.sinh(d) ); // Formula: csch(x) = 1 / sinh(x) - expression.addMathematicalUnaryFunction("cot", (d) -> 1.0 / Math.tan(Math.toRadians(d)) ); // Formula: cot(x) = cos(x) / sin(x) = 1 / tan(x) - expression.addMathematicalUnaryFunction("acot", (d) -> Math.toDegrees(Math.atan(1.0 / d)) );// Formula: acot(x) = atan(1/x) - expression.addMathematicalUnaryFunction("coth", (d) -> 1.0 / Math.tanh(d) ); // Formula: coth(x) = 1 / tanh(x) - expression.addMathematicalUnaryFunction("asinh", (d) -> Math.log(d + (Math.sqrt(Math.pow(d, 2) + 1)))); // Formula: asinh(x) = ln(x + sqrt(x^2 + 1)) - expression.addMathematicalUnaryFunction("acosh", (d) -> Math.log(d + (Math.sqrt(Math.pow(d, 2) - 1)))); // Formula: acosh(x) = ln(x + sqrt(x^2 - 1)) - expression.addMathematicalUnaryFunction("atanh", (d) -> // Formula: atanh(x) = 0.5*ln((1 + x)/(1 - x)) - { - if (Math.abs(d) > 1 || Math.abs(d) == 1) - throw new InternalExpressionException("Number must be |x| < 1"); - return 0.5 * Math.log((1 + d) / (1 - d)); - }); - expression.addMathematicalUnaryFunction("rad", Math::toRadians); - expression.addMathematicalUnaryFunction("deg", Math::toDegrees); - expression.addMathematicalUnaryFunction("ln", Math::log); - expression.addMathematicalUnaryFunction("ln1p", Math::log1p); - expression.addMathematicalUnaryFunction("log10", Math::log10); - expression.addMathematicalUnaryFunction("log", a -> Math.log(a)/Math.log(2)); - expression.addMathematicalUnaryFunction("log1p", x -> Math.log1p(x)/Math.log(2)); - expression.addMathematicalUnaryFunction("sqrt", Math::sqrt); - expression.addMathematicalUnaryFunction("abs", Math::abs); - expression.addMathematicalUnaryFunction("round", (d) -> (double)Math.round(d)); - expression.addMathematicalUnaryFunction("floor", Math::floor); - expression.addMathematicalUnaryFunction("ceil", Math::ceil); - - expression.addLazyFunction("mandelbrot", 3, (c, t, lv) -> { - double a0 = NumericValue.asNumber(lv.get(0).evalValue(c)).getDouble(); - double b0 = NumericValue.asNumber(lv.get(1).evalValue(c)).getDouble(); - long maxiter = NumericValue.asNumber(lv.get(2).evalValue(c)).getLong(); - double a = 0.0D; - double b = 0.0D; - long iter = 0; - while(a*a+b*b<4 && iter < maxiter) - { - double temp = a*a-b*b+a0; - b = 2*a*b+b0; - a = temp; - iter++; - } - long iFinal = iter; - return (cc, tt) -> new NumericValue(iFinal); - }); - - expression.addFunction("max", (lv) -> - { - if (lv.size() == 0) - throw new InternalExpressionException("'max' requires at least one parameter"); - Value max = null; - if (lv.size()==1 && lv.get(0) instanceof ListValue) - lv = ((ListValue) lv.get(0)).getItems(); - for (Value parameter : lv) - { - if (max == null || parameter.compareTo(max) > 0) max = parameter; - } - return max; - }); - - expression.addFunction("min", (lv) -> - { - if (lv.size() == 0) - throw new InternalExpressionException("'min' requires at least one parameter"); - Value min = null; - if (lv.size()==1 && lv.get(0) instanceof ListValue) - lv = ((ListValue) lv.get(0)).getItems(); - for (Value parameter : lv) - { - if (min == null || parameter.compareTo(min) < 0) min = parameter; - } - return min; - }); - - expression.addUnaryFunction("relu", (v) -> v.compareTo(Value.ZERO) < 0 ? Value.ZERO : v); + factorial = factorial * i; } + return new NumericValue(factorial); + }); + expression.addMathematicalUnaryFunction("sin", (d) -> Math.sin(Math.toRadians(d))); + expression.addMathematicalUnaryFunction("cos", (d) -> Math.cos(Math.toRadians(d))); + expression.addMathematicalUnaryFunction("tan", (d) -> Math.tan(Math.toRadians(d))); + expression.addMathematicalUnaryFunction("asin", (d) -> Math.toDegrees(Math.asin(d))); + expression.addMathematicalUnaryFunction("acos", (d) -> Math.toDegrees(Math.acos(d))); + expression.addMathematicalUnaryFunction("atan", (d) -> Math.toDegrees(Math.atan(d))); + expression.addMathematicalBinaryFunction("atan2", (d, d2) -> Math.toDegrees(Math.atan2(d, d2)) ); + expression.addMathematicalUnaryFunction("sinh", Math::sinh ); + expression.addMathematicalUnaryFunction("cosh", Math::cosh ); + expression.addMathematicalUnaryFunction("tanh", Math::tanh ); + expression.addMathematicalUnaryFunction("sec", (d) -> 1.0 / Math.cos(Math.toRadians(d)) ); // Formula: sec(x) = 1 / cos(x) + expression.addMathematicalUnaryFunction("csc", (d) -> 1.0 / Math.sin(Math.toRadians(d)) ); // Formula: csc(x) = 1 / sin(x) + expression.addMathematicalUnaryFunction("sech", (d) -> 1.0 / Math.cosh(d) ); // Formula: sech(x) = 1 / cosh(x) + expression.addMathematicalUnaryFunction("csch", (d) -> 1.0 / Math.sinh(d) ); // Formula: csch(x) = 1 / sinh(x) + expression.addMathematicalUnaryFunction("cot", (d) -> 1.0 / Math.tan(Math.toRadians(d)) ); // Formula: cot(x) = cos(x) / sin(x) = 1 / tan(x) + expression.addMathematicalUnaryFunction("acot", (d) -> Math.toDegrees(Math.atan(1.0 / d)) );// Formula: acot(x) = atan(1/x) + expression.addMathematicalUnaryFunction("coth", (d) -> 1.0 / Math.tanh(d) ); // Formula: coth(x) = 1 / tanh(x) + expression.addMathematicalUnaryFunction("asinh", (d) -> Math.log(d + (Math.sqrt(Math.pow(d, 2) + 1)))); // Formula: asinh(x) = ln(x + sqrt(x^2 + 1)) + expression.addMathematicalUnaryFunction("acosh", (d) -> Math.log(d + (Math.sqrt(Math.pow(d, 2) - 1)))); // Formula: acosh(x) = ln(x + sqrt(x^2 - 1)) + expression.addMathematicalUnaryFunction("atanh", (d) -> // Formula: atanh(x) = 0.5*ln((1 + x)/(1 - x)) + { + if (Math.abs(d) > 1 || Math.abs(d) == 1) + throw new InternalExpressionException("Number must be |x| < 1"); + return 0.5 * Math.log((1 + d) / (1 - d)); + }); + expression.addMathematicalUnaryFunction("rad", Math::toRadians); + expression.addMathematicalUnaryFunction("deg", Math::toDegrees); + expression.addMathematicalUnaryFunction("ln", Math::log); + expression.addMathematicalUnaryFunction("ln1p", Math::log1p); + expression.addMathematicalUnaryFunction("log10", Math::log10); + expression.addMathematicalUnaryFunction("log", a -> Math.log(a)/Math.log(2)); + expression.addMathematicalUnaryFunction("log1p", x -> Math.log1p(x)/Math.log(2)); + expression.addMathematicalUnaryFunction("sqrt", Math::sqrt); + expression.addMathematicalUnaryFunction("abs", Math::abs); + expression.addMathematicalUnaryFunction("round", (d) -> (double)Math.round(d)); + expression.addMathematicalUnaryFunction("floor", Math::floor); + expression.addMathematicalUnaryFunction("ceil", Math::ceil); + + expression.addLazyFunction("mandelbrot", 3, (c, t, lv) -> { + double a0 = NumericValue.asNumber(lv.get(0).evalValue(c)).getDouble(); + double b0 = NumericValue.asNumber(lv.get(1).evalValue(c)).getDouble(); + long maxiter = NumericValue.asNumber(lv.get(2).evalValue(c)).getLong(); + double a = 0.0D; + double b = 0.0D; + long iter = 0; + while(a*a+b*b<4 && iter < maxiter) + { + double temp = a*a-b*b+a0; + b = 2*a*b+b0; + a = temp; + iter++; + } + long iFinal = iter; + return (cc, tt) -> new NumericValue(iFinal); + }); + + expression.addFunction("max", (lv) -> + { + if (lv.size() == 0) + throw new InternalExpressionException("'max' requires at least one parameter"); + Value max = null; + if (lv.size()==1 && lv.get(0) instanceof ListValue) + lv = ((ListValue) lv.get(0)).getItems(); + for (Value parameter : lv) + { + if (max == null || parameter.compareTo(max) > 0) max = parameter; + } + return max; + }); + + expression.addFunction("min", (lv) -> + { + if (lv.size() == 0) + throw new InternalExpressionException("'min' requires at least one parameter"); + Value min = null; + if (lv.size()==1 && lv.get(0) instanceof ListValue) + lv = ((ListValue) lv.get(0)).getItems(); + for (Value parameter : lv) + { + if (min == null || parameter.compareTo(min) < 0) min = parameter; + } + return min; + }); + + expression.addUnaryFunction("relu", (v) -> v.compareTo(Value.ZERO) < 0 ? Value.ZERO : v); + } } diff --git a/src/main/java/carpet/script/language/ControlFlow.java b/src/main/java/carpet/script/language/ControlFlow.java index 127db614..524cf4ca 100644 --- a/src/main/java/carpet/script/language/ControlFlow.java +++ b/src/main/java/carpet/script/language/ControlFlow.java @@ -64,7 +64,5 @@ public class ControlFlow { return (c_, t_) -> val; } }); - - } } diff --git a/src/main/java/carpet/script/language/DataStructures.java b/src/main/java/carpet/script/language/DataStructures.java index 380b6af2..484e33f7 100644 --- a/src/main/java/carpet/script/language/DataStructures.java +++ b/src/main/java/carpet/script/language/DataStructures.java @@ -51,13 +51,15 @@ public class DataStructures { return new StringValue(toJoin.stream().map(Value::getString).collect(Collectors.joining(delimiter))); }); - expression.addBinaryFunction("split", (d, v) -> { + expression.addBinaryFunction("split", (d, v) -> + { String delimiter = d.getString(); String hwat = v.getString(); return ListValue.wrap(Arrays.stream(hwat.split(delimiter)).map(StringValue::new).collect(Collectors.toList())); }); - expression.addFunction("slice", (lv) -> { + expression.addFunction("slice", (lv) -> + { if (lv.size() != 2 && lv.size() != 3) throw new InternalExpressionException("'slice' takes 2 or 3 arguments"); @@ -144,19 +146,22 @@ public class DataStructures { return (cc, tt) -> ret; }); - expression.addUnaryFunction("keys", v -> { + expression.addUnaryFunction("keys", v -> + { if (v instanceof MapValue) return new ListValue(((MapValue) v).getMap().keySet()); return Value.NULL; }); - expression.addUnaryFunction("values", v -> { + expression.addUnaryFunction("values", v -> + { if (v instanceof MapValue) return new ListValue(((MapValue) v).getMap().values()); return Value.NULL; }); - expression.addUnaryFunction("pairs", v -> { + expression.addUnaryFunction("pairs", v -> + { if (v instanceof MapValue) return ListValue.wrap(((MapValue) v).getMap().entrySet().stream().map( (p) -> ListValue.of(p.getKey(), p.getValue()) diff --git a/src/main/java/carpet/script/language/Functions.java b/src/main/java/carpet/script/language/Functions.java index 851dfb84..5afa634d 100644 --- a/src/main/java/carpet/script/language/Functions.java +++ b/src/main/java/carpet/script/language/Functions.java @@ -36,7 +36,8 @@ public class Functions { return (cc, tt) -> list; }); - expression.addLazyFunctionWithDelegation("call",-1, (c, t, expr, tok, lv) -> { // adjust based on c + expression.addLazyFunctionWithDelegation("call",-1, (c, t, expr, tok, lv) -> + { // adjust based on c if (lv.size() == 0) throw new InternalExpressionException("'call' expects at least function name to call"); //lv.remove(lv.size()-1); // aint gonna cut it // maybe it will because of the eager eval changes @@ -70,6 +71,7 @@ public class Functions { Value retval = new FunctionSignatureValue(name, args, globals); return (cc, tt) -> retval; }); + expression.addLazyFunction("outer", 1, (c, t, lv) -> { if (t != Context.LOCALIZATION) throw new InternalExpressionException("Outer scoping of variables is only possible in function signatures"); @@ -93,6 +95,5 @@ public class Functions { }); expression.addFunction("return", (lv) -> { throw new ReturnStatement(lv.size()==0?Value.NULL:lv.get(0));} ); - } } diff --git a/src/main/java/carpet/script/language/Loops.java b/src/main/java/carpet/script/language/Loops.java index 8d103bdc..aa5f4f66 100644 --- a/src/main/java/carpet/script/language/Loops.java +++ b/src/main/java/carpet/script/language/Loops.java @@ -21,13 +21,15 @@ public class Loops { // condition and expression will get a bound '_i' // returns last successful expression or false // while(cond, limit, expr) => ?? - expression.addFunction("break", lv -> { + expression.addFunction("break", lv -> + { if (lv.size()==0) throw new BreakStatement(null); if (lv.size()==1) throw new BreakStatement(lv.get(0)); throw new InternalExpressionException("'break' can only be called with zero or one argument"); }); - expression.addFunction("continue", lv -> { + expression.addFunction("continue", lv -> + { if (lv.size()==0) throw new ContinueStatement(null); if (lv.size()==1) throw new ContinueStatement(lv.get(0)); throw new InternalExpressionException("'continue' can only be called with zero or one argument"); @@ -273,7 +275,8 @@ public class Loops { }); // runs traditional for(init, condition, increment, body) tri-argument for loop with body in between - expression.addLazyFunction("c_for", 4, (c, t, lv) -> { + expression.addLazyFunction("c_for", 4, (c, t, lv) -> + { LazyValue initial = lv.get(0); LazyValue condition = lv.get(1); LazyValue increment = lv.get(2); diff --git a/src/main/java/carpet/script/language/Sys.java b/src/main/java/carpet/script/language/Sys.java index 227f5f3c..b958effe 100644 --- a/src/main/java/carpet/script/language/Sys.java +++ b/src/main/java/carpet/script/language/Sys.java @@ -4,7 +4,6 @@ import carpet.script.Context; import carpet.script.Expression; import carpet.script.LazyValue; import carpet.script.ScriptHost; -import carpet.script.argument.FunctionArgument; import carpet.script.exception.InternalExpressionException; import carpet.script.utils.PerlinNoiseSampler; import carpet.script.utils.SimplexNoiseSampler; @@ -13,7 +12,6 @@ import carpet.script.value.ListValue; import carpet.script.value.NullValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; -import carpet.script.value.ThreadValue; import carpet.script.value.Value; import org.apache.commons.lang3.text.WordUtils; @@ -38,7 +36,8 @@ public class Sys { expression.addUnaryFunction("copy", Value::deepcopy); - expression.addLazyFunction("bool", 1, (c, t, lv) -> { + expression.addLazyFunction("bool", 1, (c, t, lv) -> + { Value v = lv.get(0).evalValue(c, Context.BOOLEAN); if (v instanceof StringValue) { @@ -51,7 +50,9 @@ public class Sys { Value retval = new NumericValue(v.getBoolean()); return (cc, tt) -> retval; }); - expression.addUnaryFunction("number", v -> { + + expression.addUnaryFunction("number", v -> + { if (v instanceof NumericValue) { return v; @@ -65,6 +66,7 @@ public class Sys { return Value.NULL; } }); + expression.addFunction("str", lv -> { if (lv.size() == 0) @@ -174,9 +176,9 @@ public class Sys { }); expression.addUnaryFunction("type", v -> new StringValue(v.getTypeString())); - expression.addUnaryFunction("length", v -> new NumericValue(v.length())); - expression.addLazyFunction("rand", -1, (c, t, lv) -> { + expression.addLazyFunction("rand", -1, (c, t, lv) -> + { int argsize = lv.size(); Random randomizer = Sys.randomizer; if (argsize != 1 && argsize != 2) @@ -199,7 +201,8 @@ public class Sys { return (cc, tt) -> retval; }); - expression.addLazyFunction("perlin", -1, (c, t, lv) -> { + expression.addLazyFunction("perlin", -1, (c, t, lv) -> + { PerlinNoiseSampler sampler; Value x, y, z; @@ -242,7 +245,8 @@ public class Sys { return (cc, tt) -> ret; }); - expression.addLazyFunction("simplex", -1, (c, t, lv) -> { + expression.addLazyFunction("simplex", -1, (c, t, lv) -> + { SimplexNoiseSampler sampler; Value x, y, z; @@ -373,7 +377,8 @@ public class Sys { return (cc, tt) -> res; }); - expression.addLazyFunction("var", 1, (c, t, lv) -> { + expression.addLazyFunction("var", 1, (c, t, lv) -> + { String varname = lv.get(0).evalValue(c).getString(); return expression.getOrSetAnyVariable(c, varname); }); @@ -418,7 +423,8 @@ public class Sys { }); //deprecate - expression.addLazyFunction("vars", 1, (c, t, lv) -> { + expression.addLazyFunction("vars", 1, (c, t, lv) -> + { String prefix = lv.get(0).evalValue(c).getString(); List values = new ArrayList<>(); if (prefix.startsWith("global")) @@ -433,67 +439,6 @@ public class Sys { return (cc, tt) -> retval; }); - expression.addLazyFunctionWithDelegation("task", -1, (c, t, expr, tok, lv) -> { - if (lv.size() == 0) - throw new InternalExpressionException("'task' requires at least function to call as a parameter"); - FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, true, false); - Value queue = Value.NULL; - if (lv.size() > functionArgument.offset) queue = lv.get(functionArgument.offset).evalValue(c); - ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, functionArgument.args); - Thread.yield(); - return (cc, tt) -> thread; - }); - - expression.addFunction("task_count", (lv) -> - { - if (lv.size() > 0) - { - return new NumericValue(ThreadValue.taskCount(lv.get(0))); - } - return new NumericValue(ThreadValue.taskCount()); - }); - - expression.addUnaryFunction("task_value", (v) -> { - if (!(v instanceof ThreadValue)) - throw new InternalExpressionException("'task_value' could only be used with a task value"); - return ((ThreadValue) v).getValue(); - }); - - expression.addUnaryFunction("task_join", (v) -> { - if (!(v instanceof ThreadValue)) - throw new InternalExpressionException("'task_join' could only be used with a task value"); - return ((ThreadValue) v).join(); - }); - - expression.addLazyFunction("task_dock", 1, (c, t, lv) -> { - // pass through placeholder - // implmenetation should dock the task on the main thread. - return lv.get(0); - }); - - expression.addUnaryFunction("task_completed", (v) -> { - if (!(v instanceof ThreadValue)) - throw new InternalExpressionException("'task_completed' could only be used with a task value"); - return new NumericValue(((ThreadValue) v).isFinished()); - }); - - expression.addLazyFunction("synchronize", -1, (c, t, lv) -> - { - if (lv.size() == 0) throw new InternalExpressionException("'synchronize' require at least an expression to synchronize"); - Value lockValue = Value.NULL; - int ind = 0; - if (lv.size() == 2) - { - lockValue = lv.get(0).evalValue(c); - ind = 1; - } - synchronized (ThreadValue.getLock(lockValue)) - { - Value ret = lv.get(ind).evalValue(c, t); - return (_c, _t) -> ret; - } - }); - expression.addLazyFunction("system_variable_get", -1, (c, t, lv) -> { if (lv.size() == 0) throw new InternalExpressionException("'system_variable_get' expects at least a key to be fetched"); @@ -515,7 +460,5 @@ public class Sys { if (res!=null) return (cc, tt) -> res; return (cc, tt) -> Value.NULL; }); - - } } diff --git a/src/main/java/carpet/script/language/Threading.java b/src/main/java/carpet/script/language/Threading.java new file mode 100644 index 00000000..40e4f23b --- /dev/null +++ b/src/main/java/carpet/script/language/Threading.java @@ -0,0 +1,80 @@ +package carpet.script.language; + +import carpet.script.Expression; +import carpet.script.argument.FunctionArgument; +import carpet.script.exception.InternalExpressionException; +import carpet.script.value.NumericValue; +import carpet.script.value.ThreadValue; +import carpet.script.value.Value; + +public class Threading +{ + public static void apply(Expression expression) + { + expression.addLazyFunctionWithDelegation("task", -1, (c, t, expr, tok, lv) -> + { + if (lv.size() == 0) + throw new InternalExpressionException("'task' requires at least function to call as a parameter"); + FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, true, false); + Value queue = Value.NULL; + if (lv.size() > functionArgument.offset) queue = lv.get(functionArgument.offset).evalValue(c); + ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, functionArgument.args); + Thread.yield(); + return (cc, tt) -> thread; + }); + + expression.addFunction("task_count", (lv) -> + { + if (lv.size() > 0) + { + return new NumericValue(ThreadValue.taskCount(lv.get(0))); + } + return new NumericValue(ThreadValue.taskCount()); + }); + + expression.addUnaryFunction("task_value", (v) -> + { + if (!(v instanceof ThreadValue)) + throw new InternalExpressionException("'task_value' could only be used with a task value"); + return ((ThreadValue) v).getValue(); + }); + + expression.addUnaryFunction("task_join", (v) -> + { + if (!(v instanceof ThreadValue)) + throw new InternalExpressionException("'task_join' could only be used with a task value"); + return ((ThreadValue) v).join(); + }); + + expression.addLazyFunction("task_dock", 1, (c, t, lv) -> + { + // pass through placeholder + // implmenetation should dock the task on the main thread. + return lv.get(0); + }); + + expression.addUnaryFunction("task_completed", (v) -> + { + if (!(v instanceof ThreadValue)) + throw new InternalExpressionException("'task_completed' could only be used with a task value"); + return new NumericValue(((ThreadValue) v).isFinished()); + }); + + expression.addLazyFunction("synchronize", -1, (c, t, lv) -> + { + if (lv.size() == 0) throw new InternalExpressionException("'synchronize' require at least an expression to synchronize"); + Value lockValue = Value.NULL; + int ind = 0; + if (lv.size() == 2) + { + lockValue = lv.get(0).evalValue(c); + ind = 1; + } + synchronized (ThreadValue.getLock(lockValue)) + { + Value ret = lv.get(ind).evalValue(c, t); + return (_c, _t) -> ret; + } + }); + } +} diff --git a/src/main/java/carpet/script/utils/WorldTools.java b/src/main/java/carpet/script/utils/WorldTools.java index d6d5b11d..c32d94fc 100644 --- a/src/main/java/carpet/script/utils/WorldTools.java +++ b/src/main/java/carpet/script/utils/WorldTools.java @@ -2,11 +2,14 @@ package carpet.script.utils; import carpet.fakes.MinecraftServerInterface; import com.google.common.collect.ImmutableList; +import net.minecraft.network.packet.s2c.play.ChunkDataS2CPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.WorldGenerationProgressListener; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; import net.minecraft.util.Util; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryKey; @@ -16,6 +19,7 @@ import net.minecraft.world.biome.source.BiomeAccess; import net.minecraft.world.biome.source.VanillaLayeredBiomeSource; import net.minecraft.world.border.WorldBorderListener; import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.WorldChunk; import net.minecraft.world.dimension.DimensionOptions; import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.gen.GeneratorOptions; @@ -128,6 +132,23 @@ public class WorldTools return true; } + public static void forceChunkUpdate(BlockPos pos, ServerWorld world) + { + WorldChunk worldChunk = world.getChunkManager().getWorldChunk(pos.getX()>>4, pos.getZ()>>4, false); + if (worldChunk != null) + { + int vd = world.getServer().getPlayerManager().getViewDistance() * 16; + int vvd = vd * vd; + List nearbyPlayers = world.getPlayers(p -> pos.getSquaredDistance(p.getX(), pos.getY(), p.getZ(), true) < vvd); + if (!nearbyPlayers.isEmpty()) + { + ChunkDataS2CPacket packet = new ChunkDataS2CPacket(worldChunk, 65535); + ChunkPos chpos = new ChunkPos(pos); + nearbyPlayers.forEach(p -> p.networkHandler.sendPacket(packet)); + } + } + } + private static class NoopWorldGenerationProgressListener implements WorldGenerationProgressListener { diff --git a/src/main/java/carpet/script/value/ValueConversions.java b/src/main/java/carpet/script/value/ValueConversions.java index afcf4a67..778b8226 100644 --- a/src/main/java/carpet/script/value/ValueConversions.java +++ b/src/main/java/carpet/script/value/ValueConversions.java @@ -8,17 +8,23 @@ import net.minecraft.entity.ai.pathing.PathNode; import net.minecraft.entity.damage.DamageSource; import net.minecraft.server.world.ServerWorld; +import net.minecraft.structure.StructurePiece; +import net.minecraft.structure.StructureStart; import net.minecraft.util.Identifier; import net.minecraft.util.dynamic.GlobalPos; +import net.minecraft.util.math.BlockBox; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryKey; import net.minecraft.world.World; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -101,15 +107,15 @@ public class ValueConversions { GlobalPos pos = (GlobalPos)v; return ofGlobalPos(pos); - }; + } if (v instanceof Entity) { return new EntityValue((Entity)v); - }; + } if (v instanceof BlockPos) { return new BlockValue(null, (ServerWorld) e.getEntityWorld(), (BlockPos) v); - }; + } if (v instanceof Number) { return new NumericValue(((Number) v).doubleValue()); @@ -141,7 +147,7 @@ public class ValueConversions if (v instanceof WalkTarget) { return ListValue.of( - new BlockValue(null, (ServerWorld) e.getEntityWorld(), ((LookTarget)v).getBlockPos()), + new BlockValue(null, (ServerWorld) e.getEntityWorld(), ((WalkTarget)v).getLookTarget().getBlockPos()), new NumericValue(((WalkTarget) v).getSpeed()), new NumericValue(((WalkTarget) v).getCompletionRange()) ); @@ -175,4 +181,28 @@ public class ValueConversions new StringValue(uuid.toString()) ); } + + public static Value fromStructure(StructureStart structure) + { + if (structure == null || structure == StructureStart.DEFAULT) return Value.NULL; + List pieces = new ArrayList<>(); + for (StructurePiece piece : structure.getChildren()) + { + BlockBox box = piece.getBoundingBox(); + pieces.add(ListValue.of( + new StringValue( NBTSerializableValue.nameFromRegistryId(Registry.STRUCTURE_PIECE.getId(piece.getType()))), + (piece.getFacing()== null)?Value.NULL: new StringValue(piece.getFacing().getName()), + ListValue.fromTriple(box.minX, box.minY, box.minZ), + ListValue.fromTriple(box.maxX, box.maxY, box.maxZ) + )); + } + BlockBox boundingBox = structure.getBoundingBox(); + Map ret = new HashMap<>(); + ret.put(new StringValue("box"), ListValue.of( + ListValue.fromTriple(boundingBox.minX, boundingBox.minY, boundingBox.minZ), + ListValue.fromTriple(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ) + )); + ret.put(new StringValue("pieces"), ListValue.wrap(pieces)); + return MapValue.wrap(ret); + } }