From cda2d4688c6561fec23fdaa5538a55d9faee604d Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 16 Mar 2021 21:20:02 -0700 Subject: [PATCH] implement DynamicBlockFunction --- .../structures/script/StructureScript.java | 5 +- .../script/builders/BlockFunctionBuilder.java | 12 +++-- .../functions/AbstractBlockFunction.java | 54 +++++++++++++++++++ .../script/functions/BlockFunction.java | 39 ++------------ .../functions/DynamicBlockFunction.java | 31 +++++++++++ 5 files changed, 101 insertions(+), 40 deletions(-) create mode 100644 common/src/main/java/com/dfsek/terra/api/structures/script/functions/AbstractBlockFunction.java create mode 100644 common/src/main/java/com/dfsek/terra/api/structures/script/functions/DynamicBlockFunction.java diff --git a/common/src/main/java/com/dfsek/terra/api/structures/script/StructureScript.java b/common/src/main/java/com/dfsek/terra/api/structures/script/StructureScript.java index c06d3d813..391713edb 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/script/StructureScript.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/script/StructureScript.java @@ -59,7 +59,8 @@ public class StructureScript { functionRegistry.forEach(parser::registerFunction); // Register registry functions. - parser.registerFunction("block", new BlockFunctionBuilder(main)) + parser.registerFunction("block", new BlockFunctionBuilder(main, false)) + .registerFunction("dynamicBlock", new BlockFunctionBuilder(main, true)) .registerFunction("check", new CheckFunctionBuilder(main)) .registerFunction("structure", new StructureFunctionBuilder(registry, main)) .registerFunction("randomInt", new RandomFunctionBuilder()) @@ -148,7 +149,7 @@ public class StructureScript { private boolean applyBlock(TerraImplementationArguments arguments) { try { - return !block.apply(arguments).getLevel().equals(Block.ReturnLevel.FAIL); + return block.apply(arguments).getLevel() != Block.ReturnLevel.FAIL; } catch(RuntimeException e) { main.logger().severe("Failed to generate structure at " + arguments.getBuffer().getOrigin() + ": " + e.getMessage()); main.getDebugLogger().stack(e); diff --git a/common/src/main/java/com/dfsek/terra/api/structures/script/builders/BlockFunctionBuilder.java b/common/src/main/java/com/dfsek/terra/api/structures/script/builders/BlockFunctionBuilder.java index 41c4a0dfe..0f05d2636 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/script/builders/BlockFunctionBuilder.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/script/builders/BlockFunctionBuilder.java @@ -5,24 +5,30 @@ import com.dfsek.terra.api.structures.parser.exceptions.ParseException; import com.dfsek.terra.api.structures.parser.lang.Returnable; import com.dfsek.terra.api.structures.parser.lang.constants.BooleanConstant; import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.api.structures.script.functions.AbstractBlockFunction; import com.dfsek.terra.api.structures.script.functions.BlockFunction; +import com.dfsek.terra.api.structures.script.functions.DynamicBlockFunction; import com.dfsek.terra.api.structures.tokenizer.Position; import java.util.List; -public class BlockFunctionBuilder implements FunctionBuilder { +public class BlockFunctionBuilder implements FunctionBuilder { private final TerraPlugin main; + private final boolean dynamic; - public BlockFunctionBuilder(TerraPlugin main) { + public BlockFunctionBuilder(TerraPlugin main, boolean dynamic) { this.main = main; + this.dynamic = dynamic; } @SuppressWarnings("unchecked") @Override - public BlockFunction build(List> argumentList, Position position) throws ParseException { + public AbstractBlockFunction build(List> argumentList, Position position) throws ParseException { if(argumentList.size() < 4) throw new ParseException("Expected data", position); Returnable booleanReturnable = new BooleanConstant(true, position); if(argumentList.size() == 5) booleanReturnable = (Returnable) argumentList.get(4); + if(dynamic) + return new DynamicBlockFunction((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), (Returnable) argumentList.get(2), (Returnable) argumentList.get(3), booleanReturnable, main, position); return new BlockFunction((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), (Returnable) argumentList.get(2), (Returnable) argumentList.get(3), booleanReturnable, main, position); } diff --git a/common/src/main/java/com/dfsek/terra/api/structures/script/functions/AbstractBlockFunction.java b/common/src/main/java/com/dfsek/terra/api/structures/script/functions/AbstractBlockFunction.java new file mode 100644 index 000000000..b3ff81c62 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/structures/script/functions/AbstractBlockFunction.java @@ -0,0 +1,54 @@ +package com.dfsek.terra.api.structures.script.functions; + +import com.dfsek.terra.api.TerraPlugin; +import com.dfsek.terra.api.math.vector.Vector2; +import com.dfsek.terra.api.math.vector.Vector3; +import com.dfsek.terra.api.platform.block.BlockData; +import com.dfsek.terra.api.structures.parser.lang.ImplementationArguments; +import com.dfsek.terra.api.structures.parser.lang.Returnable; +import com.dfsek.terra.api.structures.parser.lang.functions.Function; +import com.dfsek.terra.api.structures.parser.lang.variables.Variable; +import com.dfsek.terra.api.structures.script.TerraImplementationArguments; +import com.dfsek.terra.api.structures.structure.RotationUtil; +import com.dfsek.terra.api.structures.structure.buffer.items.BufferedBlock; +import com.dfsek.terra.api.structures.tokenizer.Position; +import net.jafama.FastMath; + +import java.util.Map; + +public abstract class AbstractBlockFunction implements Function { + protected final Returnable x, y, z; + protected final Returnable blockData; + protected final TerraPlugin main; + private final Returnable overwrite; + private final Position position; + + protected AbstractBlockFunction(Returnable x, Returnable y, Returnable z, Returnable blockData, Returnable overwrite, TerraPlugin main, Position position) { + this.x = x; + this.y = y; + this.z = z; + this.blockData = blockData; + this.overwrite = overwrite; + this.main = main; + this.position = position; + } + + void setBlock(ImplementationArguments implementationArguments, Map> variableMap, TerraImplementationArguments arguments, BlockData rot) { + Vector2 xz = new Vector2(x.apply(implementationArguments, variableMap).doubleValue(), z.apply(implementationArguments, variableMap).doubleValue()); + + RotationUtil.rotateVector(xz, arguments.getRotation()); + + RotationUtil.rotateBlockData(rot, arguments.getRotation().inverse()); + arguments.getBuffer().addItem(new BufferedBlock(rot, overwrite.apply(implementationArguments, variableMap), main, arguments.isWaterlog()), new Vector3(FastMath.roundToInt(xz.getX()), y.apply(implementationArguments, variableMap).doubleValue(), FastMath.roundToInt(xz.getZ())).toLocation(arguments.getBuffer().getOrigin().getWorld())); + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/src/main/java/com/dfsek/terra/api/structures/script/functions/BlockFunction.java b/common/src/main/java/com/dfsek/terra/api/structures/script/functions/BlockFunction.java index 6f9b0d54c..22f82b720 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/script/functions/BlockFunction.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/script/functions/BlockFunction.java @@ -1,67 +1,36 @@ package com.dfsek.terra.api.structures.script.functions; import com.dfsek.terra.api.TerraPlugin; -import com.dfsek.terra.api.math.vector.Vector2; -import com.dfsek.terra.api.math.vector.Vector3; import com.dfsek.terra.api.platform.block.BlockData; import com.dfsek.terra.api.structures.parser.exceptions.ParseException; import com.dfsek.terra.api.structures.parser.lang.ImplementationArguments; import com.dfsek.terra.api.structures.parser.lang.Returnable; import com.dfsek.terra.api.structures.parser.lang.constants.ConstantExpression; -import com.dfsek.terra.api.structures.parser.lang.functions.Function; import com.dfsek.terra.api.structures.parser.lang.variables.Variable; import com.dfsek.terra.api.structures.script.TerraImplementationArguments; -import com.dfsek.terra.api.structures.structure.RotationUtil; -import com.dfsek.terra.api.structures.structure.buffer.items.BufferedBlock; import com.dfsek.terra.api.structures.tokenizer.Position; -import net.jafama.FastMath; import java.util.Map; -public class BlockFunction implements Function { +public class BlockFunction extends AbstractBlockFunction { private final BlockData data; - private final Returnable x, y, z; - private final Position position; - private final Returnable overwrite; - private final TerraPlugin main; public BlockFunction(Returnable x, Returnable y, Returnable z, Returnable data, Returnable overwrite, TerraPlugin main, Position position) throws ParseException { - this.position = position; - this.main = main; - if(!(data instanceof ConstantExpression)) throw new ParseException("Block data must be constant", data.getPosition()); + super(x, y, z, data, overwrite, main, position); + if(!(data instanceof ConstantExpression)) throw new ParseException("Block data must be constant", data.getPosition()); try { this.data = main.getWorldHandle().createBlockData(((ConstantExpression) data).getConstant()); } catch(IllegalArgumentException e) { throw new ParseException("Could not parse block data", data.getPosition(), e); } - this.x = x; - this.y = y; - this.z = z; - this.overwrite = overwrite; } @Override public Void apply(ImplementationArguments implementationArguments, Map> variableMap) { TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; BlockData rot = data.clone(); - - Vector2 xz = new Vector2(x.apply(implementationArguments, variableMap).doubleValue(), z.apply(implementationArguments, variableMap).doubleValue()); - - RotationUtil.rotateVector(xz, arguments.getRotation()); - - RotationUtil.rotateBlockData(rot, arguments.getRotation().inverse()); - arguments.getBuffer().addItem(new BufferedBlock(rot, overwrite.apply(implementationArguments, variableMap), main, arguments.isWaterlog()), new Vector3(FastMath.roundToInt(xz.getX()), y.apply(implementationArguments, variableMap).doubleValue(), FastMath.roundToInt(xz.getZ())).toLocation(arguments.getBuffer().getOrigin().getWorld())); + setBlock(implementationArguments, variableMap, arguments, rot); return null; } - - @Override - public Position getPosition() { - return position; - } - - @Override - public ReturnType returnType() { - return ReturnType.VOID; - } } diff --git a/common/src/main/java/com/dfsek/terra/api/structures/script/functions/DynamicBlockFunction.java b/common/src/main/java/com/dfsek/terra/api/structures/script/functions/DynamicBlockFunction.java new file mode 100644 index 000000000..080848345 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/structures/script/functions/DynamicBlockFunction.java @@ -0,0 +1,31 @@ +package com.dfsek.terra.api.structures.script.functions; + +import com.dfsek.terra.api.TerraPlugin; +import com.dfsek.terra.api.platform.block.BlockData; +import com.dfsek.terra.api.structures.parser.lang.ImplementationArguments; +import com.dfsek.terra.api.structures.parser.lang.Returnable; +import com.dfsek.terra.api.structures.parser.lang.variables.Variable; +import com.dfsek.terra.api.structures.script.TerraImplementationArguments; +import com.dfsek.terra.api.structures.tokenizer.Position; + +import java.util.HashMap; +import java.util.Map; + +public class DynamicBlockFunction extends AbstractBlockFunction { + private final Map data = new HashMap<>(); + private final Position position; + + + public DynamicBlockFunction(Returnable x, Returnable y, Returnable z, Returnable data, Returnable overwrite, TerraPlugin main, Position position) { + super(x, y, z, data, overwrite, main, position); + this.position = position; + } + + @Override + public Void apply(ImplementationArguments implementationArguments, Map> variableMap) { + TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; + BlockData rot = data.computeIfAbsent(blockData.apply(implementationArguments, variableMap), main.getWorldHandle()::createBlockData).clone(); + setBlock(implementationArguments, variableMap, arguments, rot); + return null; + } +}