refactor terrascript into API, loader, and function addons

This commit is contained in:
dfsek
2021-08-08 12:20:26 -07:00
parent 2b142b282f
commit 3594beb406
52 changed files with 243 additions and 267 deletions

View File

@@ -1,2 +1,3 @@
dependencies {
"shadedApi"("commons-io:commons-io:2.6")
}

View File

@@ -0,0 +1,13 @@
package com.dfsek.terra.addons.terrascript.api;
import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.structure.rotation.Rotation;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import java.util.Random;
public interface StructureScript extends Structure {
@SuppressWarnings("try")
boolean test(Vector3 location, World world, Random random, Rotation rotation);
}

View File

@@ -0,0 +1,53 @@
package com.dfsek.terra.addons.terrascript.api;
import com.dfsek.terra.addons.terrascript.api.ImplementationArguments;
import com.dfsek.terra.api.structure.buffer.Buffer;
import com.dfsek.terra.api.structure.rotation.Rotation;
import com.dfsek.terra.api.world.World;
import java.util.Random;
public class TerraImplementationArguments implements ImplementationArguments {
private final Buffer buffer;
private final Rotation rotation;
private final Random random;
private final World world;
private final int recursions;
private boolean waterlog = false;
public TerraImplementationArguments(Buffer buffer, Rotation rotation, Random random, World world, int recursions) {
this.buffer = buffer;
this.rotation = rotation;
this.random = random;
this.world = world;
this.recursions = recursions;
}
public Buffer getBuffer() {
return buffer;
}
public int getRecursions() {
return recursions;
}
public Random getRandom() {
return random;
}
public Rotation getRotation() {
return rotation;
}
public boolean isWaterlog() {
return waterlog;
}
public void setWaterlog(boolean waterlog) {
this.waterlog = waterlog;
}
public World getWorld() {
return world;
}
}

View File

@@ -0,0 +1,30 @@
package com.dfsek.terra.addons.terrascript.api.buffer;
import com.dfsek.terra.api.structure.buffer.BufferedItem;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import java.util.ArrayList;
import java.util.List;
public class Cell implements BufferedItem {
private final List<BufferedItem> items = new ArrayList<>();
private String mark = null;
@Override
public void paste(Vector3 origin, World world) {
items.forEach(item -> item.paste(origin.clone(), world));
}
public void add(BufferedItem item) {
items.add(item);
}
public String getMark() {
return mark;
}
public void setMark(String mark) {
this.mark = mark;
}
}

View File

@@ -0,0 +1,56 @@
package com.dfsek.terra.addons.terrascript.api.buffer;
import com.dfsek.terra.api.structure.buffer.Buffer;
import com.dfsek.terra.api.structure.buffer.BufferedItem;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.Chunk;
import com.dfsek.terra.api.world.World;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Buffer implementation that directly pastes to the world.
*/
public class DirectBuffer implements Buffer {
private final Vector3 origin;
private final World target;
private final Map<Vector3, String> marks = new LinkedHashMap<>();
public DirectBuffer(Vector3 origin, World target) {
this.origin = origin;
this.target = target;
}
@Override
public void paste(Vector3 origin, Chunk chunk) {
// no-op
}
@Override
public void paste(Vector3 origin, World world) {
// no-op
}
@Override
public Buffer addItem(BufferedItem item, Vector3 location) {
item.paste(origin.clone().add(location), target);
return this;
}
@Override
public Vector3 getOrigin() {
return origin;
}
@Override
public String getMark(Vector3 location) {
return marks.get(location);
}
@Override
public Buffer setMark(String mark, Vector3 location) {
marks.put(location, mark);
return this;
}
}

View File

@@ -0,0 +1,48 @@
package com.dfsek.terra.addons.terrascript.api.buffer;
import com.dfsek.terra.api.structure.buffer.Buffer;
import com.dfsek.terra.api.structure.buffer.BufferedItem;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.Chunk;
import com.dfsek.terra.api.world.World;
public class IntermediateBuffer implements Buffer {
private final Buffer original;
private final Vector3 offset;
public IntermediateBuffer(Buffer original, Vector3 offset) {
this.original = original;
this.offset = offset.clone();
}
@Override
public void paste(Vector3 origin, Chunk chunk) {
// no-op
}
@Override
public void paste(Vector3 origin, World world) {
// no-op
}
@Override
public Buffer addItem(BufferedItem item, Vector3 location) {
return original.addItem(item, location.clone().add(offset));
}
@Override
public Vector3 getOrigin() {
return original.getOrigin().clone().add(offset);
}
@Override
public String getMark(Vector3 location) {
return original.getMark(location.clone().add(offset));
}
@Override
public Buffer setMark(String mark, Vector3 location) {
original.setMark(mark, location.clone().add(offset));
return this;
}
}

View File

@@ -0,0 +1,68 @@
package com.dfsek.terra.addons.terrascript.api.buffer;
import com.dfsek.terra.api.structure.buffer.Buffer;
import com.dfsek.terra.api.structure.buffer.BufferedItem;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.Chunk;
import com.dfsek.terra.api.world.World;
import net.jafama.FastMath;
import java.util.LinkedHashMap;
import java.util.Map;
public class StructureBuffer implements Buffer {
private final Map<Vector3, Cell> bufferedItemMap = new LinkedHashMap<>();
private final Vector3 origin;
private boolean succeeded;
public StructureBuffer(Vector3 origin) {
this.origin = origin;
}
public void paste(Vector3 origin, World world) {
bufferedItemMap.forEach(((vector3, item) -> item.paste(origin.clone().add(vector3), world)));
}
public void paste(Vector3 origin, Chunk chunk) {
bufferedItemMap.forEach(((location, item) -> {
Vector3 current = origin.clone().add(location);
if(FastMath.floorDiv(current.getBlockX(), 16) != chunk.getX() || FastMath.floorDiv(current.getBlockZ(), 16) != chunk.getZ())
return;
item.paste(current, chunk.getWorld());
}));
}
@Override
public Buffer addItem(BufferedItem item, Vector3 location) {
bufferedItemMap.computeIfAbsent(location.clone(), l -> new Cell()).add(item);
return this;
}
@Override
public String getMark(Vector3 location) {
Cell cell = bufferedItemMap.get(location);
if(cell != null) {
return cell.getMark();
}
return null;
}
@Override
public Buffer setMark(String mark, Vector3 location) {
bufferedItemMap.computeIfAbsent(location.clone(), l -> new Cell()).setMark(mark);
return this;
}
public void setSucceeded(boolean succeeded) {
this.succeeded = succeeded;
}
public boolean succeeded() {
return succeeded;
}
@Override
public Vector3 getOrigin() {
return origin.clone();
}
}

View File

@@ -0,0 +1,38 @@
package com.dfsek.terra.addons.terrascript.api.buffer.items;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.block.state.properties.base.Properties;
import com.dfsek.terra.api.structure.buffer.BufferedItem;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
public class BufferedBlock implements BufferedItem {
private final BlockState data;
private final boolean overwrite;
private final TerraPlugin main;
private final boolean waterlog;
public BufferedBlock(BlockState data, boolean overwrite, TerraPlugin main, boolean waterlog) {
this.data = data;
this.overwrite = overwrite;
this.main = main;
this.waterlog = waterlog;
}
@Override
public void paste(Vector3 origin, World world) {
try {
BlockState current = world.getBlockData(origin);
if(overwrite || current.isAir()) {
if(waterlog && current.has(Properties.WATERLOGGED) && current.getBlockType().isWater()) {
current.set(Properties.WATERLOGGED, true);
}
world.setBlockData(origin, data);
}
} catch(RuntimeException e) {
main.logger().severe("Failed to place block at location " + origin + ": " + e.getMessage());
main.getDebugLogger().stack(e);
}
}
}

View File

@@ -0,0 +1,26 @@
package com.dfsek.terra.addons.terrascript.api.buffer.items;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.entity.Entity;
import com.dfsek.terra.api.entity.EntityType;
import com.dfsek.terra.api.event.events.world.generation.EntitySpawnEvent;
import com.dfsek.terra.api.structure.buffer.BufferedItem;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
public class BufferedEntity implements BufferedItem {
private final EntityType type;
private final TerraPlugin main;
public BufferedEntity(EntityType type, TerraPlugin main) {
this.type = type;
this.main = main;
}
@Override
public void paste(Vector3 origin, World world) {
Entity entity = world.spawnEntity(origin.clone().add(0.5, 0, 0.5), type);
main.getEventManager().callEvent(new EntitySpawnEvent(entity.world().getConfig().getPack(), entity));
}
}

View File

@@ -0,0 +1,47 @@
package com.dfsek.terra.addons.terrascript.api.buffer.items;
import com.dfsek.terra.addons.terrascript.api.StructureScript;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.block.entity.BlockEntity;
import com.dfsek.terra.api.block.entity.Container;
import com.dfsek.terra.api.event.events.world.generation.LootPopulateEvent;
import com.dfsek.terra.api.structure.LootTable;
import com.dfsek.terra.api.structure.buffer.BufferedItem;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import java.util.Random;
public class BufferedLootApplication implements BufferedItem {
private final LootTable table;
private final TerraPlugin main;
private final StructureScript structure;
public BufferedLootApplication(LootTable table, TerraPlugin main, StructureScript structure) {
this.table = table;
this.main = main;
this.structure = structure;
}
@Override
public void paste(Vector3 origin, World world) {
try {
BlockEntity data = world.getBlockState(origin);
if(!(data instanceof Container)) {
main.logger().severe("Failed to place loot at " + origin + "; block " + data + " is not container.");
return;
}
Container container = (Container) data;
LootPopulateEvent event = new LootPopulateEvent(container, table, world.getConfig().getPack(), structure);
main.getEventManager().callEvent(event);
if(event.isCancelled()) return;
event.getTable().fillInventory(container.getInventory(), new Random(origin.hashCode()));
data.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply loot at " + origin + ": " + e.getMessage());
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,26 @@
package com.dfsek.terra.addons.terrascript.api.buffer.items;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.structure.buffer.BufferedItem;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
public class BufferedPulledBlock implements BufferedItem {
private final BlockState data;
public BufferedPulledBlock(BlockState data) {
this.data = data;
}
@Override
public void paste(Vector3 origin, World world) {
Vector3 mutable = origin.clone();
while(mutable.getY() > world.getMinHeight()) {
if(!world.getBlockData(mutable).isAir()) {
world.setBlockData(mutable, data);
break;
}
mutable.subtract(0, 1, 0);
}
}
}

View File

@@ -0,0 +1,29 @@
package com.dfsek.terra.addons.terrascript.api.buffer.items;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.block.entity.BlockEntity;
import com.dfsek.terra.api.structure.buffer.BufferedItem;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
public class BufferedStateManipulator implements BufferedItem {
private final TerraPlugin main;
private final String data;
public BufferedStateManipulator(TerraPlugin main, String state) {
this.main = main;
this.data = state;
}
@Override
public void paste(Vector3 origin, World world) {
try {
BlockEntity state = world.getBlockState(origin);
state.applyState(data);
state.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply BlockState at " + origin + ": " + e.getMessage());
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,32 @@
package com.dfsek.terra.addons.terrascript.api.lang;
import com.dfsek.terra.addons.terrascript.api.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.api.Position;
import com.dfsek.terra.addons.terrascript.api.lang.Returnable;
import com.dfsek.terra.addons.terrascript.api.lang.Variable;
import java.util.Map;
public abstract class ConstantExpression<T> implements Returnable<T> {
private final T constant;
private final Position position;
public ConstantExpression(T constant, Position position) {
this.constant = constant;
this.position = position;
}
@Override
public T apply(ImplementationArguments implementationArguments, Map<String, Variable<?>> variableMap) {
return constant;
}
@Override
public Position getPosition() {
return position;
}
public T getConstant() {
return constant;
}
}

View File

@@ -2,6 +2,7 @@ package com.dfsek.terra.addons.terrascript.api.lang;
import com.dfsek.terra.addons.terrascript.api.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.api.Position;
import com.dfsek.terra.api.properties.Context;
import java.util.Map;