Merge branch 'master' into 1.16
# Conflicts: # src/main/java/carpet/script/CarpetExpression.java # src/main/java/carpet/script/utils/ShapeDispatcher.java # src/main/java/carpet/script/utils/ShapesRenderer.java
This commit is contained in:
commit
9aa580cfa5
19 files changed
+1042
-265
No files matched your search
@@ -8,6 +8,7 @@ import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.value.BlockValue;
|
||||
import carpet.script.value.EntityValue;
|
||||
import carpet.script.value.ListValue;
|
||||
import carpet.script.value.MapValue;
|
||||
import carpet.script.value.NumericValue;
|
||||
import carpet.script.value.StringValue;
|
||||
import carpet.script.value.Value;
|
||||
@@ -19,8 +20,10 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.command.arguments.ParticleArgumentType;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.DoubleTag;
|
||||
import net.minecraft.nbt.FloatTag;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.StringTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.particle.ParticleEffect;
|
||||
@@ -28,13 +31,17 @@ import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.World;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -51,23 +58,90 @@ public class ShapeDispatcher
|
||||
{
|
||||
private static final Map<String, ParticleEffect> particleCache = new HashMap<>();
|
||||
|
||||
public static void sendShape(List<ServerPlayerEntity> players, ExpiringShape shape, Map<String, Value> params)
|
||||
public static Pair<ExpiringShape,Map<String, Value>> fromFunctionArgs(
|
||||
CarpetContext cc,
|
||||
List<Value> lv,
|
||||
ServerPlayerEntity[] playerRef
|
||||
)
|
||||
{
|
||||
Consumer<ServerPlayerEntity> alternative = null;
|
||||
CompoundTag tag = null;
|
||||
if (lv.size() < 3) throw new InternalExpressionException("'draw_shape' takes at least three parameters, shape name, duration, and its params");
|
||||
String shapeType = lv.get(0).getString();
|
||||
Value duration = NumericValue.asNumber(lv.get(1), "duration");
|
||||
Map<String, Value> params;
|
||||
if (lv.size() == 3)
|
||||
{
|
||||
Value paramValue = lv.get(2);
|
||||
if (paramValue instanceof MapValue)
|
||||
{
|
||||
params = new HashMap<>();
|
||||
((MapValue) paramValue).getMap().entrySet().forEach(e -> params.put(e.getKey().getString(),e.getValue()));
|
||||
}
|
||||
else if (paramValue instanceof ListValue)
|
||||
{
|
||||
params = parseParams(((ListValue) paramValue).getItems());
|
||||
}
|
||||
else throw new InternalExpressionException("Parameters for 'draw_shape' need to be defined either in a list or a map");
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Value> paramList = new ArrayList<>();
|
||||
for (int i=2; i < lv.size(); i++) paramList.add(lv.get(i));
|
||||
params = ShapeDispatcher.parseParams(paramList);
|
||||
}
|
||||
params.putIfAbsent("dim", new StringValue(cc.s.getWorld().getDimension().getType().toString()));
|
||||
params.putIfAbsent("duration", duration);
|
||||
|
||||
if (params.containsKey("player"))
|
||||
{
|
||||
ServerPlayerEntity player = EntityValue.getPlayerByValue(cc.s.getMinecraftServer(), params.get("player"));
|
||||
if (player == null)
|
||||
throw new InternalExpressionException("'player' parameter needs to represent an existing player");
|
||||
params.remove("player");
|
||||
playerRef[0] = player;
|
||||
}
|
||||
return Pair.of(ShapeDispatcher.create(cc, shapeType, params), params);
|
||||
}
|
||||
|
||||
public static void sendShape(List<ServerPlayerEntity> players, List<Pair<ExpiringShape,Map<String, Value>>> shapes)
|
||||
{
|
||||
List<ServerPlayerEntity> clientPlayers = new ArrayList<>();
|
||||
List<ServerPlayerEntity> alternativePlayers = new ArrayList<>();
|
||||
for (ServerPlayerEntity player : players)
|
||||
{
|
||||
if (ServerNetworkHandler.validCarpetPlayers.contains(player))
|
||||
{
|
||||
if (tag == null) tag = ExpiringShape.toTag(params);
|
||||
ServerNetworkHandler.sendCustomCommand(player,"scShape", tag);
|
||||
clientPlayers.add(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (alternative == null) alternative = shape.alternative();
|
||||
alternative.accept(player);
|
||||
alternativePlayers.add(player);
|
||||
}
|
||||
}
|
||||
if (!clientPlayers.isEmpty())
|
||||
{
|
||||
|
||||
ListTag tag = new ListTag();
|
||||
int tagcount = 0;
|
||||
for (Pair<ExpiringShape, Map<String, Value>> s : shapes)
|
||||
{
|
||||
tag.add(ExpiringShape.toTag(s.getRight())); // 4000 shapes limit boxes
|
||||
if (tagcount++>1000)
|
||||
{
|
||||
tagcount = 0;
|
||||
Tag finalTag = tag;
|
||||
clientPlayers.forEach( p -> ServerNetworkHandler.sendCustomCommand(p, "scShapes", finalTag));
|
||||
tag = new ListTag();
|
||||
}
|
||||
}
|
||||
Tag finalTag = tag;
|
||||
if (tag.size() > 0) clientPlayers.forEach( p -> ServerNetworkHandler.sendCustomCommand(p, "scShapes", finalTag));
|
||||
}
|
||||
if (!alternativePlayers.isEmpty())
|
||||
{
|
||||
List<Consumer<ServerPlayerEntity>> alternatives = new ArrayList<>();
|
||||
shapes.forEach(s -> alternatives.add(s.getLeft().alternative()));
|
||||
alternativePlayers.forEach(p -> alternatives.forEach( a -> a.accept(p)));
|
||||
}
|
||||
}
|
||||
|
||||
public static ParticleEffect getParticleData(String name)
|
||||
@@ -160,6 +234,7 @@ public class ShapeDispatcher
|
||||
put("line", creator(Line::new));
|
||||
put("box", creator(Box::new));
|
||||
put("sphere", creator(Sphere::new));
|
||||
put("cylinder", creator(Cylinder::new));
|
||||
}};
|
||||
private static Function<Map<String, Value>,ExpiringShape> creator(Supplier<ExpiringShape> shapeFactory)
|
||||
{
|
||||
@@ -176,9 +251,11 @@ public class ShapeDispatcher
|
||||
protected float fr, fg, fb, fa;
|
||||
protected int fillColor;
|
||||
protected int duration = 0;
|
||||
private int key;
|
||||
private long key;
|
||||
protected int followEntity;
|
||||
protected RegistryKey<World> entityDimension;
|
||||
protected String snapTo;
|
||||
protected boolean snapX, snapY, snapZ;
|
||||
protected RegistryKey<World> shapeDimension;
|
||||
|
||||
|
||||
protected ExpiringShape() { }
|
||||
@@ -216,7 +293,7 @@ public class ShapeDispatcher
|
||||
|
||||
duration = NumericValue.asNumber(options.get("duration")).getInt();
|
||||
|
||||
lineWidth = NumericValue.asNumber(options.getOrDefault("width", optional.get("width"))).getFloat();
|
||||
lineWidth = NumericValue.asNumber(options.getOrDefault("line", optional.get("line"))).getFloat();
|
||||
|
||||
fillColor = NumericValue.asNumber(options.getOrDefault("fill", optional.get("fill"))).getInt();
|
||||
this.fr = (float)(fillColor >> 24 & 0xFF) / 255.0F;
|
||||
@@ -232,18 +309,33 @@ public class ShapeDispatcher
|
||||
|
||||
key = 0;
|
||||
followEntity = -1;
|
||||
entityDimension = null;
|
||||
shapeDimension = RegistryKey.of(Registry.DIMENSION, new Identifier(options.get("dim").getString()));
|
||||
if (options.containsKey("follow"))
|
||||
{
|
||||
followEntity = NumericValue.asNumber(options.getOrDefault("follow", optional.get("follow"))).getInt();
|
||||
entityDimension = RegistryKey.of(Registry.DIMENSION, new Identifier(options.get("dim").getString()));
|
||||
snapTo = options.getOrDefault("snap", optional.get("snap")).getString().toLowerCase(Locale.ROOT);
|
||||
snapX = snapTo.contains("x");
|
||||
snapY = snapTo.contains("y");
|
||||
snapZ = snapTo.contains("z");
|
||||
}
|
||||
}
|
||||
public int getExpiry() { return duration; }
|
||||
public Vec3d toAbsolute(Entity e, Vec3d vec)
|
||||
public Vec3d toAbsolute(Entity e, Vec3d vec, float partialTick)
|
||||
{
|
||||
return e.getPos().add(vec);
|
||||
return vec.add(
|
||||
snapX?MathHelper.lerp(partialTick, e.prevX, e.getX()):0.0,
|
||||
snapY?MathHelper.lerp(partialTick, e.prevY, e.getY()):0.0,
|
||||
snapZ?MathHelper.lerp(partialTick, e.prevZ, e.getZ()):0.0
|
||||
);
|
||||
}
|
||||
public Vec3d relativiseRender(World world, Vec3d vec, float partialTick)
|
||||
{
|
||||
if (followEntity <= 0) return vec;
|
||||
Entity e = world.getEntityById(followEntity);
|
||||
if (e == null) return vec;
|
||||
return toAbsolute(e, vec, partialTick);
|
||||
}
|
||||
|
||||
public Vec3d vecFromValue(Value value)
|
||||
{
|
||||
if (!(value instanceof ListValue)) throw new InternalExpressionException("decoded value of "+value.getPrettyString()+" is not a triple");
|
||||
@@ -256,19 +348,20 @@ public class ShapeDispatcher
|
||||
}
|
||||
|
||||
public abstract Consumer<ServerPlayerEntity> alternative();
|
||||
public int key()
|
||||
public long key()
|
||||
{
|
||||
if (key!=0) return key;
|
||||
key = calcKey();
|
||||
return key;
|
||||
}
|
||||
protected int calcKey()
|
||||
{
|
||||
int hash = 17;
|
||||
hash = 31*hash + color;
|
||||
hash = 31*hash + followEntity;
|
||||
hash = 31*hash + Float.hashCode(lineWidth);
|
||||
if (fa != 0.0) hash = 31*hash + fillColor;
|
||||
protected long calcKey()
|
||||
{ // using FNV-1a algorithm
|
||||
long hash = -3750763034362895579L;
|
||||
hash ^= shapeDimension.hashCode(); hash *= 1099511628211L;
|
||||
hash ^= color; hash *= 1099511628211L;
|
||||
hash ^= followEntity; hash *= 1099511628211L;
|
||||
hash ^= Float.hashCode(lineWidth); hash *= 1099511628211L;
|
||||
if (fa != 0.0) { hash = 31*hash + fillColor; hash *= 1099511628211L; }
|
||||
return hash;
|
||||
}
|
||||
// list of params that need to be there
|
||||
@@ -276,8 +369,9 @@ public class ShapeDispatcher
|
||||
private final Map<String, Value> optional = ImmutableMap.of(
|
||||
"color", new NumericValue(-1),
|
||||
"follow", new NumericValue(-1),
|
||||
"width", new NumericValue(2.0),
|
||||
"fill", new NumericValue(0xffffff00)
|
||||
"line", new NumericValue(2.0),
|
||||
"fill", new NumericValue(0xffffff00),
|
||||
"snap", new StringValue("xyz")
|
||||
);
|
||||
protected Set<String> requiredParams() {return required;}
|
||||
// list of params that can be there, with defaults
|
||||
@@ -308,6 +402,7 @@ public class ShapeDispatcher
|
||||
super.init(options);
|
||||
from = vecFromValue(options.get("from"));
|
||||
to = vecFromValue(options.get("to"));
|
||||
if (from.equals(to)) throw new InternalExpressionException("Box dimensions are invalid - cannot draw a zero-size boxes");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -318,26 +413,26 @@ public class ShapeDispatcher
|
||||
double density = Math.max(2.0, from.distanceTo(to) /50) / (a+0.1);
|
||||
return p ->
|
||||
{
|
||||
if (followEntity == -1)
|
||||
if (p.dimension == shapeDimension)
|
||||
{
|
||||
particleMesh(Collections.singletonList(p), particle, density, from, to);
|
||||
return;
|
||||
particleMesh(
|
||||
Collections.singletonList(p),
|
||||
particle,
|
||||
density,
|
||||
relativiseRender(p.getServerWorld(), from, 0),
|
||||
relativiseRender(p.getServerWorld(), to, 0)
|
||||
);
|
||||
}
|
||||
Entity e = p.getServer().getWorld(entityDimension).getEntityById(followEntity);
|
||||
if (e == null) return;
|
||||
Vec3d rel1 = toAbsolute(e, from);
|
||||
Vec3d rel2 = toAbsolute(e, to);
|
||||
particleMesh(Collections.singletonList(p), particle, density, rel1, rel2);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calcKey()
|
||||
public long calcKey()
|
||||
{
|
||||
int hash = super.calcKey();
|
||||
hash = 31*hash + 1;
|
||||
hash = 31*hash + from.hashCode();
|
||||
hash = 31*hash + to.hashCode();
|
||||
long hash = super.calcKey();
|
||||
hash ^= 1; hash *= 1099511628211L;
|
||||
hash ^= from.hashCode(); hash *= 1099511628211L;
|
||||
hash ^= to.hashCode(); hash *= 1099511628211L;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -391,6 +486,7 @@ public class ShapeDispatcher
|
||||
super.init(options);
|
||||
from = vecFromValue(options.get("from"));
|
||||
to = vecFromValue(options.get("to"));
|
||||
if (from.equals(to)) throw new InternalExpressionException("Line dimensions are invalid - cannot draw a zero-length lines");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -399,29 +495,26 @@ public class ShapeDispatcher
|
||||
String particleName = String.format(Locale.ROOT , "dust %.1f %.1f %.1f 1.0", r, g, b);
|
||||
ParticleEffect particle = getParticleData(particleName);
|
||||
double density = Math.max(2.0, from.distanceTo(to) /50) / (a+0.1);
|
||||
|
||||
return p ->
|
||||
{
|
||||
if (followEntity == -1)
|
||||
{
|
||||
drawParticleLine(Collections.singletonList(p), particle, from, to, density);
|
||||
return;
|
||||
}
|
||||
|
||||
Entity e = p.getServer().getWorld(entityDimension).getEntityById(followEntity);
|
||||
if (e == null) return;
|
||||
Vec3d rel1 = toAbsolute(e, from);
|
||||
Vec3d rel2 = toAbsolute(e, to);
|
||||
drawParticleLine(Collections.singletonList(p), particle, rel1, rel2, density);
|
||||
if (p.dimension == shapeDimension) drawParticleLine(
|
||||
Collections.singletonList(p),
|
||||
particle,
|
||||
relativiseRender(p.getServerWorld(), from, 0),
|
||||
relativiseRender(p.getServerWorld(), to, 0),
|
||||
density
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calcKey()
|
||||
public long calcKey()
|
||||
{
|
||||
int hash = super.calcKey();
|
||||
hash = 31*hash + 2;
|
||||
hash = 31*hash + from.hashCode();
|
||||
hash = 31*hash + to.hashCode();
|
||||
long hash = super.calcKey();
|
||||
hash ^= 2; hash *= 1099511628211L;
|
||||
hash ^= from.hashCode(); hash *= 1099511628211L;
|
||||
hash ^= to.hashCode(); hash *= 1099511628211L;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -462,24 +555,18 @@ public class ShapeDispatcher
|
||||
@Override
|
||||
public Consumer<ServerPlayerEntity> alternative() { return p ->
|
||||
{
|
||||
if (p.dimension != shapeDimension) return;
|
||||
String particleName = String.format(Locale.ROOT , "dust %.1f %.1f %.1f 1.0", r, g, b);
|
||||
ParticleEffect particle = getParticleData(particleName);
|
||||
int partno = Math.min(1000,20*subdivisions);
|
||||
Random rand = p.world.getRandom();
|
||||
ServerWorld world = p.getServerWorld();
|
||||
|
||||
double ccx, ccy, ccz;
|
||||
if (followEntity == -1)
|
||||
{
|
||||
ccx = center.x; ccy = center.y; ccz = center.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
Entity e = p.getServer().getWorld(entityDimension).getEntityById(followEntity);
|
||||
if (e == null) return;
|
||||
Vec3d rel1 = toAbsolute(e, center);
|
||||
ccx = (float)rel1.x; ccy = (float)rel1.y; ccz = (float)rel1.z;
|
||||
}
|
||||
Vec3d ccenter = relativiseRender(world, center, 0 );
|
||||
|
||||
double ccx = ccenter.x;
|
||||
double ccy = ccenter.y;
|
||||
double ccz = ccenter.z;
|
||||
|
||||
for (int i=0; i<partno; i++)
|
||||
{
|
||||
@@ -496,13 +583,117 @@ public class ShapeDispatcher
|
||||
};}
|
||||
|
||||
@Override
|
||||
public int calcKey()
|
||||
public long calcKey()
|
||||
{
|
||||
int hash = super.calcKey();
|
||||
hash = 31*hash + 3;
|
||||
hash = 31*hash + center.hashCode();
|
||||
hash = 31*hash + Double.hashCode(radius);
|
||||
hash = 31*hash + level;
|
||||
long hash = super.calcKey();
|
||||
hash ^= 3; hash *= 1099511628211L;
|
||||
hash ^= center.hashCode(); hash *= 1099511628211L;
|
||||
hash ^= Double.hashCode(radius); hash *= 1099511628211L;
|
||||
hash ^= level; hash *= 1099511628211L;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
public static class Cylinder extends ExpiringShape
|
||||
{
|
||||
private final Set<String> required = ImmutableSet.of("center", "radius");
|
||||
private final Map<String, Value> optional = ImmutableMap.of(
|
||||
"level", Value.ZERO,
|
||||
"height", Value.ZERO,
|
||||
"axis", new StringValue("y")
|
||||
);
|
||||
@Override
|
||||
protected Set<String> requiredParams() { return Sets.union(super.requiredParams(), required); }
|
||||
@Override
|
||||
protected Set<String> optionalParams() { return Sets.union(super.optionalParams(), optional.keySet()); }
|
||||
|
||||
Vec3d center;
|
||||
float height;
|
||||
float radius;
|
||||
int level;
|
||||
int subdivisions;
|
||||
Direction.Axis axis;
|
||||
|
||||
private Cylinder() { super(); }
|
||||
|
||||
@Override
|
||||
protected void init(Map<String, Value> options)
|
||||
{
|
||||
super.init(options);
|
||||
center = vecFromValue(options.get("center"));
|
||||
radius = NumericValue.asNumber(options.get("radius")).getFloat();
|
||||
level = NumericValue.asNumber(options.getOrDefault("level", optional.get("level"))).getInt();
|
||||
subdivisions = level;
|
||||
if (subdivisions <= 0)
|
||||
{
|
||||
subdivisions = Math.max(10, (int)(10*Math.sqrt(radius)));
|
||||
}
|
||||
height = NumericValue.asNumber(options.getOrDefault("height", optional.get("height"))).getFloat();
|
||||
axis = Direction.Axis.fromName(options.getOrDefault("axis", optional.get("axis")).getString());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Consumer<ServerPlayerEntity> alternative() { return p ->
|
||||
{
|
||||
String particleName = String.format(Locale.ROOT , "dust %.1f %.1f %.1f 1.0", r, g, b);
|
||||
ParticleEffect particle = getParticleData(particleName);
|
||||
int partno = (int)Math.min(1000,Math.sqrt(20*subdivisions*(1+height)));
|
||||
Random rand = p.world.getRandom();
|
||||
ServerWorld world = p.getServerWorld();
|
||||
|
||||
Vec3d ccenter = relativiseRender(world, center, 0 );
|
||||
|
||||
double ccx = ccenter.x;
|
||||
double ccy = ccenter.y;
|
||||
double ccz = ccenter.z;
|
||||
|
||||
if (axis == Direction.Axis.Y)
|
||||
{
|
||||
for (int i=0; i<partno; i++)
|
||||
{
|
||||
float d = rand.nextFloat()*height;
|
||||
float phi = (float)(2*Math.PI*rand.nextDouble());
|
||||
double x = radius * MathHelper.cos(phi);
|
||||
double y = d;
|
||||
double z = radius * MathHelper.sin(phi);
|
||||
world.spawnParticles(p, particle, true, x+ccx, y+ccy, z+ccz, 1, 0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
else if (axis== Direction.Axis.X)
|
||||
{
|
||||
for (int i=0; i<partno; i++)
|
||||
{
|
||||
float d = rand.nextFloat()*height;
|
||||
float phi = (float)(2*Math.PI*rand.nextDouble());
|
||||
double x = d;
|
||||
double y = radius * MathHelper.cos(phi);
|
||||
double z = radius * MathHelper.sin(phi);
|
||||
world.spawnParticles(p, particle, true, x+ccx, y+ccy, z+ccz, 1, 0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
else // Z
|
||||
{
|
||||
for (int i=0; i<partno; i++)
|
||||
{
|
||||
float d = rand.nextFloat()*height;
|
||||
float phi = (float)(2*Math.PI*rand.nextDouble());
|
||||
double x = radius * MathHelper.sin(phi);
|
||||
double y = radius * MathHelper.cos(phi);
|
||||
double z = d;
|
||||
world.spawnParticles(p, particle, true, x+ccx, y+ccy, z+ccz, 1, 0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
};}
|
||||
|
||||
@Override
|
||||
public long calcKey()
|
||||
{
|
||||
long hash = super.calcKey();
|
||||
hash ^= 3; hash *= 1099511628211L;
|
||||
hash ^= center.hashCode(); hash *= 1099511628211L;
|
||||
hash ^= Double.hashCode(radius); hash *= 1099511628211L;
|
||||
hash ^= Double.hashCode(height); hash *= 1099511628211L;
|
||||
hash ^= level; hash *= 1099511628211L;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -513,10 +704,11 @@ public class ShapeDispatcher
|
||||
public static Map<String, Param> of = new HashMap<String, Param>(){{
|
||||
put("shape", new ShapeParam());
|
||||
put("dim", new DimensionParam());
|
||||
put("duration", new PositiveIntParam("duration"));
|
||||
put("duration", new NonNegativeIntParam("duration"));
|
||||
put("color", new ColorParam("color"));
|
||||
put("follow", new EntityParam("follow"));
|
||||
put("width", new PositiveFloatParam("width"));
|
||||
put("snap", new StringChoiceParam("snap", "xyz", "xz", "yz", "xy", "x", "y", "z"));
|
||||
put("line", new PositiveFloatParam("line"));
|
||||
put("fill", new ColorParam("fill"));
|
||||
|
||||
put("from", new Vec3Param("from", false));
|
||||
@@ -524,6 +716,9 @@ public class ShapeDispatcher
|
||||
put("center", new Vec3Param("center", false));
|
||||
put("radius", new PositiveFloatParam("radius"));
|
||||
put("level", new PositiveIntParam("level"));
|
||||
put("height", new NonNegativeFloatParam("height"));
|
||||
put("axis", new StringChoiceParam("axis", "x", "y", "z"));
|
||||
put("points", new PointsParam("points"));
|
||||
}};
|
||||
protected String id;
|
||||
protected Param(String id)
|
||||
@@ -545,6 +740,24 @@ public class ShapeDispatcher
|
||||
public Value decode(Tag tag) { return new StringValue(tag.asString()); }
|
||||
}
|
||||
|
||||
public static class StringChoiceParam extends StringParam
|
||||
{
|
||||
private Set<String> options;
|
||||
public StringChoiceParam(String id, String ... options)
|
||||
{
|
||||
super(id);
|
||||
this.options = Sets.newHashSet(options);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Value validate(Map<String, Value> options, CarpetContext cc, Value value)
|
||||
{
|
||||
if (this.options.contains(value.getString())) return value;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DimensionParam extends StringParam
|
||||
{
|
||||
protected DimensionParam() { super("dim"); }
|
||||
@@ -593,7 +806,7 @@ public class ShapeDispatcher
|
||||
@Override
|
||||
public Value decode(Tag tag) { return new NumericValue(((FloatTag)tag).getFloat()); }
|
||||
@Override
|
||||
public Tag toTag(Value value) { return FloatTag.of(NumericValue.asNumber(value).getFloat()); }
|
||||
public Tag toTag(Value value) { return FloatTag.of(NumericValue.asNumber(value, id).getFloat()); }
|
||||
|
||||
}
|
||||
public static class PositiveIntParam extends PositiveParam
|
||||
@@ -602,9 +815,37 @@ public class ShapeDispatcher
|
||||
@Override
|
||||
public Value decode(Tag tag) { return new NumericValue(((IntTag)tag).getInt()); }
|
||||
@Override
|
||||
public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value).getInt()); }
|
||||
public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value, id).getInt()); }
|
||||
|
||||
}
|
||||
public static class NonNegativeIntParam extends NumericParam
|
||||
{
|
||||
protected NonNegativeIntParam(String id) { super(id); }
|
||||
@Override
|
||||
public Value decode(Tag tag) { return new NumericValue(((IntTag)tag).getInt()); }
|
||||
@Override
|
||||
public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value, id).getInt()); }
|
||||
@Override public Value validate(Map<String, Value> options, CarpetContext cc, Value value)
|
||||
{
|
||||
Value ret = super.validate(options, cc, value);
|
||||
if (((NumericValue)ret).getDouble()<0) throw new InternalExpressionException("'"+id+"' should be non-negative");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
public static class NonNegativeFloatParam extends NumericParam
|
||||
{
|
||||
protected NonNegativeFloatParam(String id) { super(id); }
|
||||
@Override
|
||||
public Value decode(Tag tag) { return new NumericValue(((FloatTag)tag).getFloat()); }
|
||||
@Override
|
||||
public Tag toTag(Value value) { return FloatTag.of(NumericValue.asNumber(value, id).getFloat()); }
|
||||
@Override public Value validate(Map<String, Value> options, CarpetContext cc, Value value)
|
||||
{
|
||||
Value ret = super.validate(options, cc, value);
|
||||
if (((NumericValue)ret).getDouble()<0) throw new InternalExpressionException("'"+id+"' should be non-negative");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Vec3Param extends Param
|
||||
{
|
||||
@@ -616,13 +857,17 @@ public class ShapeDispatcher
|
||||
}
|
||||
@Override
|
||||
public Value validate(Map<String, Value> options, CarpetContext cc, Value value)
|
||||
{
|
||||
return validate(this, options, cc, value, roundsUpForBlocks);
|
||||
}
|
||||
public static Value validate(Param p, Map<String, Value> options, CarpetContext cc, Value value, boolean roundsUp)
|
||||
{
|
||||
if (value instanceof BlockValue)
|
||||
{
|
||||
if (options.containsKey("follow"))
|
||||
throw new InternalExpressionException(id+" parameter cannot use blocks as positions for relative positioning due to 'follow' attribute being present");
|
||||
throw new InternalExpressionException(p.id+" parameter cannot use blocks as positions for relative positioning due to 'follow' attribute being present");
|
||||
BlockPos pos = ((BlockValue) value).getPos();
|
||||
int offset = roundsUpForBlocks?1:0;
|
||||
int offset = roundsUp?1:0;
|
||||
return ListValue.of(
|
||||
new NumericValue(pos.getX()+offset),
|
||||
new NumericValue(pos.getY()+offset),
|
||||
@@ -632,18 +877,18 @@ public class ShapeDispatcher
|
||||
if (value instanceof ListValue)
|
||||
{
|
||||
List<Value> values = ((ListValue) value).getItems();
|
||||
if (values.size()!=3) throw new InternalExpressionException("'"+id+"' requires 3 numerical values");
|
||||
if (values.size()!=3) throw new InternalExpressionException("'"+p.id+"' requires 3 numerical values");
|
||||
for (Value component : values)
|
||||
{
|
||||
if (!(component instanceof NumericValue))
|
||||
throw new InternalExpressionException("'"+id+"' requires 3 numerical values");
|
||||
throw new InternalExpressionException("'"+p.id+"' requires 3 numerical values");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if (value instanceof EntityValue)
|
||||
{
|
||||
if (options.containsKey("follow"))
|
||||
throw new InternalExpressionException(id+" parameter cannot use entity as positions for relative positioning due to 'follow' attribute being present");
|
||||
throw new InternalExpressionException(p.id+" parameter cannot use entity as positions for relative positioning due to 'follow' attribute being present");
|
||||
Entity e = ((EntityValue) value).getEntity();
|
||||
return ListValue.of(
|
||||
new NumericValue(e.getX()),
|
||||
@@ -652,29 +897,81 @@ public class ShapeDispatcher
|
||||
);
|
||||
}
|
||||
CarpetSettings.LOG.error("Value: "+value.getString());
|
||||
throw new InternalExpressionException("'"+id+"' requires a triple, block or entity to indicate position");
|
||||
throw new InternalExpressionException("'"+p.id+"' requires a triple, block or entity to indicate position");
|
||||
}
|
||||
|
||||
public Value decode(Tag tag)
|
||||
{
|
||||
CompoundTag ctag = (CompoundTag)tag;
|
||||
ListTag ctag = (ListTag)tag;
|
||||
return ListValue.of(
|
||||
new NumericValue(ctag.getDouble("x")),
|
||||
new NumericValue(ctag.getDouble("y")),
|
||||
new NumericValue(ctag.getDouble("z"))
|
||||
new NumericValue(ctag.getDouble(0)),
|
||||
new NumericValue(ctag.getDouble(1)),
|
||||
new NumericValue(ctag.getDouble(2))
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public Tag toTag(Value value)
|
||||
{
|
||||
List<Value> lv = ((ListValue)value).getItems();
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putDouble("x", NumericValue.asNumber(lv.get(0)).getDouble());
|
||||
tag.putDouble("y", NumericValue.asNumber(lv.get(1)).getDouble());
|
||||
tag.putDouble("z", NumericValue.asNumber(lv.get(2)).getDouble());
|
||||
ListTag tag = new ListTag();
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(0), "x").getDouble()));
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(1), "y").getDouble()));
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(2), "z").getDouble()));
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PointsParam extends Param
|
||||
{
|
||||
public PointsParam(String id)
|
||||
{
|
||||
super(id);
|
||||
}
|
||||
@Override
|
||||
public Value validate(Map<String, Value> options, CarpetContext cc, Value value)
|
||||
{
|
||||
if (!(value instanceof ListValue))
|
||||
throw new InternalExpressionException(id+ " parameter should be a list");
|
||||
List<Value> points = new ArrayList<>();
|
||||
for (Value point: ((ListValue) value).getItems())
|
||||
points.add(Vec3Param.validate(this, options, cc, point, false));
|
||||
return ListValue.wrap(points);
|
||||
}
|
||||
|
||||
public Value decode(Tag tag)
|
||||
{
|
||||
ListTag ltag = (ListTag)tag;
|
||||
List<Value> points = new ArrayList<>();
|
||||
for (int i=0, ll = ltag.size(); i<ll; i++)
|
||||
{
|
||||
ListTag ptag = ltag.getList(i);
|
||||
points.add(ListValue.of(
|
||||
new NumericValue(ptag.getDouble(0)),
|
||||
new NumericValue(ptag.getDouble(1)),
|
||||
new NumericValue(ptag.getDouble(2))
|
||||
));
|
||||
}
|
||||
return ListValue.wrap(points);
|
||||
}
|
||||
@Override
|
||||
public Tag toTag(Value pointsValue)
|
||||
{
|
||||
List<Value> lv = ((ListValue)pointsValue).getItems();
|
||||
ListTag ltag = new ListTag();
|
||||
for (Value value : lv)
|
||||
{
|
||||
List<Value> coords = ((ListValue)value).getItems();
|
||||
ListTag tag = new ListTag();
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(0), "x").getDouble()));
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(1), "y").getDouble()));
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(2), "z").getDouble()));
|
||||
ltag.add(tag);
|
||||
}
|
||||
return ltag;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ColorParam extends NumericParam
|
||||
{
|
||||
protected ColorParam(String id)
|
||||
@@ -684,7 +981,7 @@ public class ShapeDispatcher
|
||||
|
||||
public Value decode(Tag tag) { return new NumericValue(((IntTag)tag).getInt()); }
|
||||
@Override
|
||||
public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value).getInt()); }
|
||||
public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value, id).getInt()); }
|
||||
}
|
||||
|
||||
public static class EntityParam extends Param
|
||||
@@ -695,7 +992,7 @@ public class ShapeDispatcher
|
||||
@Override
|
||||
public Tag toTag(Value value)
|
||||
{
|
||||
return IntTag.of(NumericValue.asNumber(value).getInt());
|
||||
return IntTag.of(NumericValue.asNumber(value, id).getInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in new issue
Block a user