semi-auto cleanup
This commit is contained in:
1 parent
cad80f82c6
commit
8f61271606
99 files changed
+11463
-8007
No files matched your search
@@ -8,21 +8,25 @@ import java.util.List;
|
||||
|
||||
public abstract class AbstractListValue extends Value implements Iterable<Value>
|
||||
{
|
||||
@Override public abstract Iterator<Value> iterator();
|
||||
public List<Value> unpack()
|
||||
{
|
||||
List<Value> retVal = Lists.newArrayList(iterator());
|
||||
final List<Value> retVal = Lists.newArrayList(iterator());
|
||||
fatality();
|
||||
return retVal;
|
||||
}
|
||||
public void fatality() { }
|
||||
public void append(Value v)
|
||||
|
||||
public void fatality()
|
||||
{
|
||||
}
|
||||
|
||||
public void append(final Value v)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot append a value to an abstract list");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value fromConstant() {
|
||||
public Value fromConstant()
|
||||
{
|
||||
return this.deepcopy();
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,14 @@ import carpet.script.exception.Throwables;
|
||||
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.commands.arguments.blocks.BlockStateParser;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -44,42 +46,51 @@ public class BlockValue extends Value
|
||||
{
|
||||
private BlockState blockState;
|
||||
private final BlockPos pos;
|
||||
@NotNull private final Level world;
|
||||
@NotNull
|
||||
private final Level world;
|
||||
private CompoundTag data;
|
||||
|
||||
public static BlockValue fromCoords(CarpetContext c, int x, int y, int z)
|
||||
public static BlockValue fromCoords(final CarpetContext c, final int x, final int y, final int z)
|
||||
{
|
||||
BlockPos pos = locateBlockPos(c, x,y,z);
|
||||
final BlockPos pos = locateBlockPos(c, x, y, z);
|
||||
return new BlockValue(null, c.level(), pos);
|
||||
}
|
||||
|
||||
private static final Map<String, BlockValue> bvCache= new HashMap<>();
|
||||
public static BlockValue fromString(String str, Level level)
|
||||
private static final Map<String, BlockValue> bvCache = new HashMap<>();
|
||||
|
||||
public static BlockValue fromString(final String str, final Level level)
|
||||
{
|
||||
try
|
||||
{
|
||||
BlockValue bv = bvCache.get(str); // [SCARY SHIT] persistent caches over server reloads
|
||||
if (bv != null) return bv;
|
||||
BlockStateParser.BlockResult foo = BlockStateParser.parseForBlock(level.registryAccess().lookupOrThrow(Registries.BLOCK), new StringReader(str), true );
|
||||
if (bv != null)
|
||||
{
|
||||
return bv;
|
||||
}
|
||||
final BlockStateParser.BlockResult foo = BlockStateParser.parseForBlock(level.registryAccess().lookupOrThrow(Registries.BLOCK), new StringReader(str), true);
|
||||
if (foo.blockState() != null)
|
||||
{
|
||||
CompoundTag bd = foo.nbt();
|
||||
if (bd == null)
|
||||
{
|
||||
bd = new CompoundTag();
|
||||
bv = new BlockValue(foo.blockState(), level, null, bd );
|
||||
if (bvCache.size()>10000)
|
||||
}
|
||||
bv = new BlockValue(foo.blockState(), level, null, bd);
|
||||
if (bvCache.size() > 10000)
|
||||
{
|
||||
bvCache.clear();
|
||||
}
|
||||
bvCache.put(str, bv);
|
||||
return bv;
|
||||
}
|
||||
}
|
||||
catch (CommandSyntaxException ignored)
|
||||
catch (final CommandSyntaxException ignored)
|
||||
{
|
||||
}
|
||||
throw new ThrowStatement(str, Throwables.UNKNOWN_BLOCK);
|
||||
}
|
||||
|
||||
public static BlockPos locateBlockPos(CarpetContext c, int xpos, int ypos, int zpos)
|
||||
public static BlockPos locateBlockPos(final CarpetContext c, final int xpos, final int ypos, final int zpos)
|
||||
{
|
||||
final BlockPos pos = c.origin();
|
||||
return new BlockPos(pos.getX() + xpos, pos.getY() + ypos, pos.getZ() + zpos);
|
||||
@@ -99,13 +110,13 @@ public class BlockValue extends Value
|
||||
throw new InternalExpressionException("Attempted to fetch block state without world or stored block state");
|
||||
}
|
||||
|
||||
public static BlockEntity getBlockEntity(Level level, BlockPos pos)
|
||||
public static BlockEntity getBlockEntity(final Level level, final BlockPos pos)
|
||||
{
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
if (serverLevel.getServer().isSameThread())
|
||||
return serverLevel.getBlockEntity(pos);
|
||||
else
|
||||
return serverLevel.getChunkAt(pos).getBlockEntity(pos, LevelChunk.EntityCreationType.IMMEDIATE);
|
||||
if (level instanceof final ServerLevel serverLevel)
|
||||
{
|
||||
return serverLevel.getServer().isSameThread()
|
||||
? serverLevel.getBlockEntity(pos)
|
||||
: serverLevel.getChunkAt(pos).getBlockEntity(pos, LevelChunk.EntityCreationType.IMMEDIATE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -115,13 +126,11 @@ public class BlockValue extends Value
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
if (data.isEmpty())
|
||||
return null;
|
||||
return data;
|
||||
return data.isEmpty() ? null : data;
|
||||
}
|
||||
if (pos != null)
|
||||
{
|
||||
BlockEntity be = getBlockEntity(world, pos);
|
||||
final BlockEntity be = getBlockEntity(world, pos);
|
||||
if (be == null)
|
||||
{
|
||||
data = new CompoundTag();
|
||||
@@ -134,7 +143,7 @@ public class BlockValue extends Value
|
||||
}
|
||||
|
||||
|
||||
public BlockValue(BlockState state, @NotNull Level world, BlockPos position)
|
||||
public BlockValue(final BlockState state, @NotNull final Level world, final BlockPos position)
|
||||
{
|
||||
this.world = world;
|
||||
blockState = state;
|
||||
@@ -142,7 +151,7 @@ public class BlockValue extends Value
|
||||
data = null;
|
||||
}
|
||||
|
||||
public BlockValue(BlockState state, @NotNull Level world, BlockPos position, CompoundTag nbt)
|
||||
public BlockValue(final BlockState state, @NotNull final Level world, final BlockPos position, final CompoundTag nbt)
|
||||
{
|
||||
this.world = world;
|
||||
blockState = state;
|
||||
@@ -154,7 +163,7 @@ public class BlockValue extends Value
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
Registry<Block> blockRegistry = world.registryAccess().registryOrThrow(Registries.BLOCK);
|
||||
final Registry<Block> blockRegistry = world.registryAccess().registryOrThrow(Registries.BLOCK);
|
||||
return nameFromRegistryId(blockRegistry.getKey(getBlockState().getBlock()));
|
||||
}
|
||||
|
||||
@@ -179,9 +188,9 @@ public class BlockValue extends Value
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
if (pos != null )
|
||||
return GlobalPos.of(world.dimension() , pos).hashCode(); //getDimension().getType()
|
||||
return ("b"+getString()).hashCode();
|
||||
return pos != null
|
||||
? GlobalPos.of(world.dimension(), pos).hashCode()
|
||||
: ("b" + getString()).hashCode();
|
||||
}
|
||||
|
||||
public BlockPos getPos()
|
||||
@@ -189,29 +198,35 @@ public class BlockValue extends Value
|
||||
return pos;
|
||||
}
|
||||
|
||||
public Level getWorld() { return world;}
|
||||
public Level getWorld()
|
||||
{
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
if (!force)
|
||||
{
|
||||
throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
}
|
||||
// follows falling block convertion
|
||||
CompoundTag tag = new CompoundTag();
|
||||
CompoundTag state = new CompoundTag();
|
||||
BlockState s = getBlockState();
|
||||
final CompoundTag tag = new CompoundTag();
|
||||
final CompoundTag state = new CompoundTag();
|
||||
final BlockState s = getBlockState();
|
||||
state.put("Name", StringTag.valueOf(world.registryAccess().registryOrThrow(Registries.BLOCK).getKey(s.getBlock()).toString()));
|
||||
Collection<Property<?>> properties = s.getProperties();
|
||||
final Collection<Property<?>> properties = s.getProperties();
|
||||
if (!properties.isEmpty())
|
||||
{
|
||||
CompoundTag props = new CompoundTag();
|
||||
for (Property<?> p: properties)
|
||||
final CompoundTag props = new CompoundTag();
|
||||
for (final Property<?> p : properties)
|
||||
{
|
||||
props.put(p.getName(), StringTag.valueOf(s.getValue(p).toString().toLowerCase(Locale.ROOT)));
|
||||
}
|
||||
state.put("Properties", props);
|
||||
}
|
||||
tag.put("BlockState", state);
|
||||
CompoundTag dataTag = getData();
|
||||
final CompoundTag dataTag = getData();
|
||||
if (dataTag != null)
|
||||
{
|
||||
tag.put("TileEntityData", dataTag);
|
||||
@@ -219,29 +234,30 @@ public class BlockValue extends Value
|
||||
return tag;
|
||||
}
|
||||
|
||||
public enum SpecificDirection {
|
||||
UP("up",0.5, 0.0, 0.5, Direction.UP),
|
||||
public enum SpecificDirection
|
||||
{
|
||||
UP("up", 0.5, 0.0, 0.5, Direction.UP),
|
||||
|
||||
UPNORTH ("up-north", 0.5, 0.0, 0.4, Direction.UP),
|
||||
UPSOUTH ("up-south", 0.5, 0.0, 0.6, Direction.UP),
|
||||
UPNORTH("up-north", 0.5, 0.0, 0.4, Direction.UP),
|
||||
UPSOUTH("up-south", 0.5, 0.0, 0.6, Direction.UP),
|
||||
UPEAST("up-east", 0.6, 0.0, 0.5, Direction.UP),
|
||||
UPWEST("up-west", 0.4, 0.0, 0.5, Direction.UP),
|
||||
|
||||
DOWN("down", 0.5, 1.0, 0.5, Direction.DOWN),
|
||||
|
||||
DOWNNORTH ("down-north", 0.5, 1.0, 0.4, Direction.DOWN),
|
||||
DOWNSOUTH ("down-south", 0.5, 1.0, 0.6, Direction.DOWN),
|
||||
DOWNNORTH("down-north", 0.5, 1.0, 0.4, Direction.DOWN),
|
||||
DOWNSOUTH("down-south", 0.5, 1.0, 0.6, Direction.DOWN),
|
||||
DOWNEAST("down-east", 0.6, 1.0, 0.5, Direction.DOWN),
|
||||
DOWNWEST("down-west", 0.4, 1.0, 0.5, Direction.DOWN),
|
||||
|
||||
|
||||
NORTH ("north", 0.5, 0.4, 1.0, Direction.NORTH),
|
||||
SOUTH ("south", 0.5, 0.4, 0.0, Direction.SOUTH),
|
||||
NORTH("north", 0.5, 0.4, 1.0, Direction.NORTH),
|
||||
SOUTH("south", 0.5, 0.4, 0.0, Direction.SOUTH),
|
||||
EAST("east", 0.0, 0.4, 0.5, Direction.EAST),
|
||||
WEST("west", 1.0, 0.4, 0.5, Direction.WEST),
|
||||
|
||||
NORTHUP ("north-up", 0.5, 0.6, 1.0, Direction.NORTH),
|
||||
SOUTHUP ("south-up", 0.5, 0.6, 0.0, Direction.SOUTH),
|
||||
NORTHUP("north-up", 0.5, 0.6, 1.0, Direction.NORTH),
|
||||
SOUTHUP("south-up", 0.5, 0.6, 0.0, Direction.SOUTH),
|
||||
EASTUP("east-up", 0.0, 0.6, 0.5, Direction.EAST),
|
||||
WESTUP("west-up", 1.0, 0.6, 0.5, Direction.WEST);
|
||||
|
||||
@@ -252,87 +268,94 @@ public class BlockValue extends Value
|
||||
private static final Map<String, SpecificDirection> DIRECTION_MAP = Arrays.stream(values()).collect(Collectors.toMap(SpecificDirection::getName, d -> d));
|
||||
|
||||
|
||||
SpecificDirection(String name, double hitx, double hity, double hitz, Direction blockFacing)
|
||||
SpecificDirection(final String name, final double hitx, final double hity, final double hitz, final Direction blockFacing)
|
||||
{
|
||||
this.name = name;
|
||||
this.hitOffset = new Vec3(hitx, hity, hitz);
|
||||
this.facing = blockFacing;
|
||||
}
|
||||
|
||||
private String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlacementContext extends BlockPlaceContext {
|
||||
public static class PlacementContext extends BlockPlaceContext
|
||||
{
|
||||
private final Direction facing;
|
||||
private final boolean sneakPlace;
|
||||
|
||||
public static PlacementContext from(Level world, BlockPos pos, String direction, boolean sneakPlace, ItemStack itemStack)
|
||||
public static PlacementContext from(final Level world, final BlockPos pos, final String direction, final boolean sneakPlace, final ItemStack itemStack)
|
||||
{
|
||||
SpecificDirection dir = SpecificDirection.DIRECTION_MAP.get(direction);
|
||||
final SpecificDirection dir = SpecificDirection.DIRECTION_MAP.get(direction);
|
||||
if (dir == null)
|
||||
throw new InternalExpressionException("unknown block placement direction: "+direction);
|
||||
BlockHitResult hitres = new BlockHitResult(Vec3.atLowerCornerOf(pos).add(dir.hitOffset), dir.facing, pos, false);
|
||||
{
|
||||
throw new InternalExpressionException("unknown block placement direction: " + direction);
|
||||
}
|
||||
final BlockHitResult hitres = new BlockHitResult(Vec3.atLowerCornerOf(pos).add(dir.hitOffset), dir.facing, pos, false);
|
||||
return new PlacementContext(world, dir.facing, sneakPlace, itemStack, hitres);
|
||||
}
|
||||
private PlacementContext(Level world_1, Direction direction_1, boolean sneakPlace, ItemStack itemStack_1, BlockHitResult hitres) {
|
||||
|
||||
private PlacementContext(final Level world_1, final Direction direction_1, final boolean sneakPlace, final ItemStack itemStack_1, final BlockHitResult hitres)
|
||||
{
|
||||
super(world_1, null, InteractionHand.MAIN_HAND, itemStack_1, hitres);
|
||||
this.facing = direction_1;
|
||||
this.sneakPlace = sneakPlace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getClickedPos() {
|
||||
boolean prevcanReplaceExisting = replaceClicked;
|
||||
public BlockPos getClickedPos()
|
||||
{
|
||||
final boolean prevcanReplaceExisting = replaceClicked;
|
||||
replaceClicked = true;
|
||||
BlockPos ret = super.getClickedPos();
|
||||
final BlockPos ret = super.getClickedPos();
|
||||
replaceClicked = prevcanReplaceExisting;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction getNearestLookingDirection() {
|
||||
public Direction getNearestLookingDirection()
|
||||
{
|
||||
return facing.getOpposite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction[] getNearestLookingDirections() {
|
||||
switch(this.facing) {
|
||||
case DOWN:
|
||||
default:
|
||||
return new Direction[]{Direction.DOWN, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP};
|
||||
case UP:
|
||||
return new Direction[]{Direction.DOWN, Direction.UP, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST};
|
||||
case NORTH:
|
||||
return new Direction[]{Direction.DOWN, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.UP, Direction.SOUTH};
|
||||
case SOUTH:
|
||||
return new Direction[]{Direction.DOWN, Direction.SOUTH, Direction.EAST, Direction.WEST, Direction.UP, Direction.NORTH};
|
||||
case WEST:
|
||||
return new Direction[]{Direction.DOWN, Direction.WEST, Direction.SOUTH, Direction.UP, Direction.NORTH, Direction.EAST};
|
||||
case EAST:
|
||||
return new Direction[]{Direction.DOWN, Direction.EAST, Direction.SOUTH, Direction.UP, Direction.NORTH, Direction.WEST};
|
||||
}
|
||||
public Direction[] getNearestLookingDirections()
|
||||
{
|
||||
return switch (this.facing)
|
||||
{
|
||||
case DOWN -> new Direction[]{Direction.DOWN, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP};
|
||||
case UP -> new Direction[]{Direction.DOWN, Direction.UP, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST};
|
||||
case NORTH -> new Direction[]{Direction.DOWN, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.UP, Direction.SOUTH};
|
||||
case SOUTH -> new Direction[]{Direction.DOWN, Direction.SOUTH, Direction.EAST, Direction.WEST, Direction.UP, Direction.NORTH};
|
||||
case WEST -> new Direction[]{Direction.DOWN, Direction.WEST, Direction.SOUTH, Direction.UP, Direction.NORTH, Direction.EAST};
|
||||
case EAST -> new Direction[]{Direction.DOWN, Direction.EAST, Direction.SOUTH, Direction.UP, Direction.NORTH, Direction.WEST};
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction getHorizontalDirection() {
|
||||
public Direction getHorizontalDirection()
|
||||
{
|
||||
return this.facing.getAxis() == Direction.Axis.Y ? Direction.NORTH : this.facing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction getNearestLookingVerticalDirection() {
|
||||
public Direction getNearestLookingVerticalDirection()
|
||||
{
|
||||
return facing.getAxis() == Axis.Y ? facing : Direction.UP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecondaryUseActive() {
|
||||
public boolean isSecondaryUseActive()
|
||||
{
|
||||
return sneakPlace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getRotation() {
|
||||
return (float)(this.facing.get2DDataValue() * 90);
|
||||
public float getRotation()
|
||||
{
|
||||
return (float) (this.facing.get2DDataValue() * 90);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,53 +11,63 @@ public class BooleanValue extends NumericValue
|
||||
public static final BooleanValue TRUE = new BooleanValue(true);
|
||||
|
||||
boolean boolValue;
|
||||
private BooleanValue(boolean boolval) {
|
||||
|
||||
private BooleanValue(final boolean boolval)
|
||||
{
|
||||
super(boolval ? 1L : 0L);
|
||||
boolValue = boolval;
|
||||
}
|
||||
|
||||
public static BooleanValue of(boolean value)
|
||||
public static BooleanValue of(final boolean value)
|
||||
{
|
||||
return value ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
return boolValue?"true":"false";
|
||||
public String getString()
|
||||
{
|
||||
return boolValue ? "true" : "false";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrettyString() {
|
||||
public String getPrettyString()
|
||||
{
|
||||
return getString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeString() {
|
||||
public String getTypeString()
|
||||
{
|
||||
return "bool";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value clone() {
|
||||
public Value clone()
|
||||
{
|
||||
return new BooleanValue(boolValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
public int hashCode()
|
||||
{
|
||||
return Boolean.hashCode(boolValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force) {
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
return ByteTag.valueOf(boolValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement toJson() {
|
||||
public JsonElement toJson()
|
||||
{
|
||||
return new JsonPrimitive(boolValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInteger() {
|
||||
public boolean isInteger()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,15 @@ package carpet.script.value;
|
||||
public interface ContainerValueInterface
|
||||
{
|
||||
boolean put(Value where, Value value);
|
||||
default boolean put(Value where, Value value, Value conditions)
|
||||
|
||||
default boolean put(final Value where, final Value value, final Value conditions)
|
||||
{
|
||||
return put(where, value);
|
||||
}
|
||||
|
||||
Value get(Value where);
|
||||
|
||||
boolean has(Value where);
|
||||
|
||||
boolean delete(Value where);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -9,51 +9,56 @@ import net.minecraft.network.chat.MutableComponent;
|
||||
public class FormattedTextValue extends StringValue
|
||||
{
|
||||
Component text;
|
||||
public FormattedTextValue(Component text)
|
||||
|
||||
public FormattedTextValue(final Component text)
|
||||
{
|
||||
super(null);
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public static Value combine(Value left, Value right) {
|
||||
MutableComponent text;
|
||||
if (left instanceof FormattedTextValue)
|
||||
public static Value combine(final Value left, final Value right)
|
||||
{
|
||||
final MutableComponent text;
|
||||
if (left instanceof final FormattedTextValue ftv)
|
||||
{
|
||||
text = ((FormattedTextValue) left).getText().copy();
|
||||
text = ftv.getText().copy();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left.isNull())
|
||||
{
|
||||
return right;
|
||||
}
|
||||
text = Component.literal(left.getString());
|
||||
}
|
||||
|
||||
if (right instanceof FormattedTextValue)
|
||||
{
|
||||
text.append(((FormattedTextValue) right).getText().copy());
|
||||
return new FormattedTextValue(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (right.isNull())
|
||||
return left;
|
||||
text.append(right.getString());
|
||||
return new FormattedTextValue(text);
|
||||
}
|
||||
}
|
||||
|
||||
public static Value of(Component text) {
|
||||
if (text == null) return Value.NULL;
|
||||
if (right instanceof final FormattedTextValue ftv)
|
||||
{
|
||||
text.append(ftv.getText().copy());
|
||||
return new FormattedTextValue(text);
|
||||
}
|
||||
if (right.isNull())
|
||||
{
|
||||
return left;
|
||||
}
|
||||
text.append(right.getString());
|
||||
return new FormattedTextValue(text);
|
||||
}
|
||||
|
||||
public static Value of(final Component text)
|
||||
{
|
||||
return text == null ? Value.NULL : new FormattedTextValue(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
public String getString()
|
||||
{
|
||||
return text.getString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean() {
|
||||
public boolean getBoolean()
|
||||
{
|
||||
return !text.getString().isEmpty();
|
||||
}
|
||||
|
||||
@@ -75,19 +80,24 @@ public class FormattedTextValue extends StringValue
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
if (!force)
|
||||
{
|
||||
throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
}
|
||||
return StringTag.valueOf(Component.Serializer.toJson(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement toJson() {
|
||||
public JsonElement toJson()
|
||||
{
|
||||
return Component.Serializer.toJsonTree(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value add(Value o) {
|
||||
public Value add(final Value o)
|
||||
{
|
||||
return combine(this, o);
|
||||
}
|
||||
|
||||
@@ -96,13 +106,14 @@ public class FormattedTextValue extends StringValue
|
||||
return Component.Serializer.toJson(text);
|
||||
}
|
||||
|
||||
public static FormattedTextValue deserialize(String serialized)
|
||||
public static FormattedTextValue deserialize(final String serialized)
|
||||
{
|
||||
return new FormattedTextValue(Component.Serializer.fromJson(serialized));
|
||||
}
|
||||
|
||||
public static Component getTextByValue(Value value) {
|
||||
return (value instanceof FormattedTextValue) ? ((FormattedTextValue) value).getText() : Component.literal(value.getString());
|
||||
public static Component getTextByValue(final Value value)
|
||||
{
|
||||
return (value instanceof final FormattedTextValue ftv) ? ftv.getText() : Component.literal(value.getString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public abstract class FrameworkValue extends Value
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
throw new UnsupportedOperationException("Scarpet language component cannot be serialized to the tag");
|
||||
}
|
||||
|
||||
@@ -9,11 +9,15 @@ public class FunctionAnnotationValue extends Value
|
||||
{
|
||||
GLOBAL, VARARG
|
||||
}
|
||||
|
||||
public Type type;
|
||||
public FunctionAnnotationValue(Value variable, Type type)
|
||||
|
||||
public FunctionAnnotationValue(final Value variable, final Type type)
|
||||
{
|
||||
if (variable.boundVariable == null)
|
||||
{
|
||||
throw new InternalExpressionException("You can only borrow variables from the outer scope");
|
||||
}
|
||||
this.boundVariable = variable.boundVariable;
|
||||
this.type = type;
|
||||
}
|
||||
@@ -37,7 +41,7 @@ public class FunctionAnnotationValue extends Value
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
throw new UnsupportedOperationException("Global value cannot be serialized to the tag");
|
||||
}
|
||||
|
||||
@@ -9,23 +9,21 @@ public class FunctionSignatureValue extends FrameworkValue
|
||||
private List<String> globals;
|
||||
private String varArgs;
|
||||
|
||||
public FunctionSignatureValue(String name, List<String> args, String varArgs, List<String> globals)
|
||||
public FunctionSignatureValue(final String name, final List<String> args, final String varArgs, final List<String> globals)
|
||||
{
|
||||
this.identifier = name;
|
||||
this.arguments = args;
|
||||
this.varArgs = varArgs;
|
||||
this.globals = globals;
|
||||
}
|
||||
public String getName()
|
||||
public String identifier()
|
||||
{
|
||||
return identifier;
|
||||
}
|
||||
public List<String> getArgs()
|
||||
public List<String> arguments()
|
||||
{
|
||||
return arguments;
|
||||
}
|
||||
public List<String> getGlobals() {return globals;}
|
||||
|
||||
|
||||
public String getVarArgs() { return varArgs;}
|
||||
public List<String> globals() {return globals;}
|
||||
public String varArgs() { return varArgs;}
|
||||
}
|
||||
@@ -4,7 +4,8 @@ import java.util.List;
|
||||
|
||||
public class FunctionUnpackedArgumentsValue extends ListValue
|
||||
{
|
||||
public FunctionUnpackedArgumentsValue(List<Value> list) {
|
||||
public FunctionUnpackedArgumentsValue(final List<Value> list)
|
||||
{
|
||||
super(list);
|
||||
}
|
||||
|
||||
@@ -17,7 +18,6 @@ public class FunctionUnpackedArgumentsValue extends ListValue
|
||||
@Override
|
||||
public Value deepcopy()
|
||||
{
|
||||
ListValue copy = (ListValue)super.deepcopy();
|
||||
return new FunctionUnpackedArgumentsValue(copy.items);
|
||||
return new FunctionUnpackedArgumentsValue(((ListValue) super.deepcopy()).items);
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,14 @@ import carpet.script.exception.ContinueStatement;
|
||||
import carpet.script.exception.ExpressionException;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.exception.ReturnStatement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.nbt.StringTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
|
||||
@@ -33,7 +35,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
private static long variantCounter = 1;
|
||||
private long variant;
|
||||
|
||||
private FunctionValue(Expression expression, Tokenizer.Token token, String name, LazyValue body, List<String> args, String varArgs)
|
||||
private FunctionValue(final Expression expression, final Tokenizer.Token token, final String name, final LazyValue body, final List<String> args, final String varArgs)
|
||||
{
|
||||
this.expression = expression;
|
||||
this.token = token;
|
||||
@@ -45,7 +47,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
variant = 0L;
|
||||
}
|
||||
|
||||
public FunctionValue(Expression expression, Tokenizer.Token token, String name, LazyValue body, List<String> args, String varArgs, Map<String, LazyValue> outerState)
|
||||
public FunctionValue(final Expression expression, final Tokenizer.Token token, final String name, final LazyValue body, final List<String> args, final String varArgs, final Map<String, LazyValue> outerState)
|
||||
{
|
||||
this.expression = expression;
|
||||
this.token = token;
|
||||
@@ -63,19 +65,27 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
return name;
|
||||
}
|
||||
|
||||
public Module getModule() {return expression.module;}
|
||||
public Module getModule()
|
||||
{
|
||||
return expression.module;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrettyString()
|
||||
{
|
||||
List<String> stringArgs= new ArrayList<>(args);
|
||||
final List<String> stringArgs = new ArrayList<>(args);
|
||||
if (outerState != null)
|
||||
{
|
||||
stringArgs.addAll(outerState.entrySet().stream().map(e ->
|
||||
"outer("+e.getKey()+") = "+e.getValue().evalValue(null).getPrettyString()).collect(Collectors.toList()));
|
||||
return (name.equals("_")?"<lambda>":name) +"("+String.join(", ",stringArgs)+")";
|
||||
"outer(" + e.getKey() + ") = " + e.getValue().evalValue(null).getPrettyString()).toList());
|
||||
}
|
||||
return (name.equals("_") ? "<lambda>" : name) + "(" + String.join(", ", stringArgs) + ")";
|
||||
}
|
||||
|
||||
public String fullName() {return (name.equals("_")?"<lambda>":name)+(expression.module == null?"":"["+expression.module.name()+"]");}
|
||||
public String fullName()
|
||||
{
|
||||
return (name.equals("_") ? "<lambda>" : name) + (expression.module == null ? "" : "[" + expression.module.name() + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean()
|
||||
@@ -86,7 +96,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
@Override
|
||||
protected Value clone()
|
||||
{
|
||||
FunctionValue ret = new FunctionValue(expression, token, name, body, args, varArgs);
|
||||
final FunctionValue ret = new FunctionValue(expression, token, name, body, args, varArgs);
|
||||
ret.outerState = this.outerState;
|
||||
ret.variant = this.variant;
|
||||
return ret;
|
||||
@@ -95,26 +105,22 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return name.hashCode()+(int)variant;
|
||||
return name.hashCode() + (int) variant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (o instanceof FunctionValue)
|
||||
return name.equals(((FunctionValue) o).name) && variant == ((FunctionValue) o).variant;
|
||||
return false;
|
||||
return o instanceof final FunctionValue fv && name.equals(fv.name) && variant == fv.variant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final Value o)
|
||||
{
|
||||
if (o instanceof FunctionValue)
|
||||
if (o instanceof final FunctionValue fv)
|
||||
{
|
||||
int nameSame = this.name.compareTo(((FunctionValue) o).name);
|
||||
if (nameSame != 0)
|
||||
return nameSame;
|
||||
return (int) (variant-((FunctionValue) o).variant);
|
||||
final int nameSame = this.name.compareTo(fv.name);
|
||||
return nameSame != 0 ? nameSame : (int) (variant - fv.variant);
|
||||
}
|
||||
return getString().compareTo(o.getString());
|
||||
}
|
||||
@@ -132,7 +138,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value slice(long from, Long to)
|
||||
public Value slice(final long from, final Long to)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot slice a function");
|
||||
}
|
||||
@@ -149,46 +155,49 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
return varArgs != null;
|
||||
}
|
||||
|
||||
public LazyValue callInContext(Context c, Context.Type type, List<Value> params)
|
||||
public LazyValue callInContext(final Context c, final Context.Type type, final List<Value> params)
|
||||
{
|
||||
try
|
||||
{
|
||||
return execute(c, type, expression, token, params);
|
||||
}
|
||||
catch (ExpressionException exc)
|
||||
catch (final ExpressionException exc)
|
||||
{
|
||||
exc.stack.add(this);
|
||||
throw exc;
|
||||
}
|
||||
catch (InternalExpressionException exc)
|
||||
catch (final InternalExpressionException exc)
|
||||
{
|
||||
exc.stack.add(this);
|
||||
throw new ExpressionException(c, expression, token, exc.getMessage(), exc.stack);
|
||||
}
|
||||
|
||||
catch (ArithmeticException exc)
|
||||
catch (final ArithmeticException exc)
|
||||
{
|
||||
throw new ExpressionException(c, expression, token, "Your math is wrong, "+exc.getMessage(), Collections.singletonList(this));
|
||||
throw new ExpressionException(c, expression, token, "Your math is wrong, " + exc.getMessage(), Collections.singletonList(this));
|
||||
}
|
||||
}
|
||||
|
||||
public void checkArgs(int candidates)
|
||||
public void checkArgs(final int candidates)
|
||||
{
|
||||
int actual = getArguments().size();
|
||||
final int actual = getArguments().size();
|
||||
|
||||
if (candidates < actual)
|
||||
{
|
||||
throw new InternalExpressionException("Function " + getPrettyString() + " requires at least " + actual + " arguments");
|
||||
}
|
||||
if (candidates > actual && getVarArgs() == null)
|
||||
{
|
||||
throw new InternalExpressionException("Function " + getPrettyString() + " requires " + actual + " arguments");
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Value> unpackArgs(List<LazyValue> lazyParams, Context c)
|
||||
public static List<Value> unpackArgs(final List<LazyValue> lazyParams, final Context c)
|
||||
{
|
||||
// TODO we shoudn't need that if all fuctions are not lazy really
|
||||
List<Value> params = new ArrayList<>();
|
||||
for (LazyValue lv : lazyParams)
|
||||
final List<Value> params = new ArrayList<>();
|
||||
for (final LazyValue lv : lazyParams)
|
||||
{
|
||||
Value param = lv.evalValue(c, Context.NONE);
|
||||
final Value param = lv.evalValue(c, Context.NONE);
|
||||
if (param instanceof FunctionUnpackedArgumentsValue)
|
||||
{
|
||||
CarpetSettings.LOG.error("How did we get here?");
|
||||
@@ -203,48 +212,51 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyValue lazyEval(Context c, Context.Type type, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams) {
|
||||
List<Value> resolvedParams = unpackArgs(lazyParams, c);
|
||||
public LazyValue lazyEval(final Context c, final Context.Type type, final Expression e, final Tokenizer.Token t, final List<LazyValue> lazyParams)
|
||||
{
|
||||
final List<Value> resolvedParams = unpackArgs(lazyParams, c);
|
||||
return execute(c, type, e, t, resolvedParams);
|
||||
}
|
||||
|
||||
public LazyValue execute(Context c, Context.Type type, Expression e, Tokenizer.Token t, List<Value> params)
|
||||
public LazyValue execute(final Context c, final Context.Type type, final Expression e, final Tokenizer.Token t, final List<Value> params)
|
||||
{
|
||||
assertArgsOk(params, (fixedArgs) ->{
|
||||
assertArgsOk(params, fixedArgs -> {
|
||||
if (fixedArgs) // wrong number of args for fixed args
|
||||
{
|
||||
throw new ExpressionException(c, e, t,
|
||||
"Incorrect number of arguments for function "+name+
|
||||
". Should be "+args.size()+", not "+params.size()+" like "+args
|
||||
"Incorrect number of arguments for function " + name +
|
||||
". Should be " + args.size() + ", not " + params.size() + " like " + args
|
||||
);
|
||||
}
|
||||
else // too few args for varargs
|
||||
{
|
||||
List<String> argList = new ArrayList<>(args);
|
||||
argList.add("... "+varArgs);
|
||||
throw new ExpressionException(c, e, t,
|
||||
"Incorrect number of arguments for function "+name+
|
||||
". Should be at least "+args.size()+", not "+params.size()+" like "+argList
|
||||
);
|
||||
}
|
||||
});
|
||||
Context newFrame = c.recreate();
|
||||
// too few args for varargs
|
||||
|
||||
if (outerState != null) outerState.forEach(newFrame::setVariable);
|
||||
for (int i=0; i<args.size(); i++)
|
||||
final List<String> argList = new ArrayList<>(args);
|
||||
argList.add("... " + varArgs);
|
||||
throw new ExpressionException(c, e, t,
|
||||
"Incorrect number of arguments for function " + name +
|
||||
". Should be at least " + args.size() + ", not " + params.size() + " like " + argList
|
||||
);
|
||||
});
|
||||
final Context newFrame = c.recreate();
|
||||
|
||||
if (outerState != null)
|
||||
{
|
||||
String arg = args.get(i);
|
||||
Value val = params.get(i).reboundedTo(arg); // todo check if we need to copy that
|
||||
outerState.forEach(newFrame::setVariable);
|
||||
}
|
||||
for (int i = 0; i < args.size(); i++)
|
||||
{
|
||||
final String arg = args.get(i);
|
||||
final Value val = params.get(i).reboundedTo(arg); // todo check if we need to copy that
|
||||
newFrame.setVariable(arg, (cc, tt) -> val);
|
||||
}
|
||||
if (varArgs != null)
|
||||
{
|
||||
List<Value> extraParams = new ArrayList<>();
|
||||
final List<Value> extraParams = new ArrayList<>();
|
||||
for (int i = args.size(), mx = params.size(); i < mx; i++)
|
||||
{
|
||||
extraParams.add(params.get(i).reboundedTo(null)); // copy by value I guess
|
||||
}
|
||||
Value rest = ListValue.wrap(extraParams).bindTo(varArgs); // didn't we just copied that?
|
||||
final Value rest = ListValue.wrap(extraParams).bindTo(varArgs); // didn't we just copied that?
|
||||
newFrame.setVariable(varArgs, (cc, tt) -> rest);
|
||||
|
||||
}
|
||||
@@ -253,15 +265,15 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
{
|
||||
retVal = body.evalValue(newFrame, type); // todo not sure if we need to propagete type / consider boolean context in defined functions - answer seems ye
|
||||
}
|
||||
catch (BreakStatement | ContinueStatement exc)
|
||||
catch (final BreakStatement | ContinueStatement exc)
|
||||
{
|
||||
throw new ExpressionException(c, e, t, "'continue' and 'break' can only be called inside loop function bodies");
|
||||
}
|
||||
catch (ReturnStatement returnStatement)
|
||||
catch (final ReturnStatement returnStatement)
|
||||
{
|
||||
retVal = returnStatement.retval;
|
||||
}
|
||||
Value otherRetVal = retVal;
|
||||
final Value otherRetVal = retVal;
|
||||
return (cc, tt) -> otherRetVal;
|
||||
}
|
||||
|
||||
@@ -269,30 +281,38 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
|
||||
public Tokenizer.Token getToken()
|
||||
{
|
||||
return token;
|
||||
}
|
||||
|
||||
public List<String> getArguments()
|
||||
{
|
||||
return args;
|
||||
}
|
||||
public String getVarArgs() {return varArgs; }
|
||||
|
||||
public String getVarArgs()
|
||||
{
|
||||
return varArgs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
if (!force)
|
||||
{
|
||||
throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
}
|
||||
return StringTag.valueOf(getString());
|
||||
}
|
||||
|
||||
public void assertArgsOk(List<?> list, Consumer<Boolean> feedback)
|
||||
public void assertArgsOk(final List<?> list, final Consumer<Boolean> feedback)
|
||||
{
|
||||
int size = list.size();
|
||||
final int size = list.size();
|
||||
if (varArgs == null && args.size() != size) // wrong number of args for fixed args
|
||||
{
|
||||
feedback.accept(true);
|
||||
|
||||
}
|
||||
else if (varArgs != null && args.size() > size) // too few args for varargs
|
||||
{
|
||||
@@ -301,12 +321,14 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pure() {
|
||||
public boolean pure()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transitive() {
|
||||
public boolean transitive()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,23 @@ package carpet.script.value;
|
||||
|
||||
public class LContainerValue extends FrameworkValue
|
||||
{
|
||||
private ContainerValueInterface container;
|
||||
private Value address;
|
||||
private final ContainerValueInterface container;
|
||||
private final Value address;
|
||||
public static final LContainerValue NULL_CONTAINER = new LContainerValue(null, null);
|
||||
|
||||
public LContainerValue(ContainerValueInterface c, Value v)
|
||||
public LContainerValue(final ContainerValueInterface c, final Value v)
|
||||
{
|
||||
container = c;
|
||||
address = v;
|
||||
}
|
||||
|
||||
public ContainerValueInterface getContainer() {return container; }
|
||||
public Value getAddress() {return address; }
|
||||
public ContainerValueInterface container()
|
||||
{
|
||||
return container;
|
||||
}
|
||||
|
||||
public Value address()
|
||||
{
|
||||
return address;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,41 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.minecraft.nbt.StringTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
|
||||
public abstract class LazyListValue extends AbstractListValue implements Iterator<Value>
|
||||
{
|
||||
public static LazyListValue rangeDouble(double from, double to, double step)
|
||||
public static LazyListValue rangeDouble(final double from, final double to, final double step)
|
||||
{
|
||||
return new LazyListValue()
|
||||
{
|
||||
{
|
||||
if (step == 0)
|
||||
{
|
||||
throw new InternalExpressionException("Range will never end with a zero step");
|
||||
}
|
||||
this.start = from;
|
||||
this.current = this.start;
|
||||
this.limit = to;
|
||||
this.stepp = step;
|
||||
}
|
||||
|
||||
private final double start;
|
||||
private double current;
|
||||
private final double limit;
|
||||
private final double stepp;
|
||||
|
||||
@Override
|
||||
public Value next()
|
||||
{
|
||||
Value val = new NumericValue(current);
|
||||
final Value val = new NumericValue(current);
|
||||
current += stepp;
|
||||
return val;
|
||||
}
|
||||
@@ -43,36 +49,41 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return stepp > 0?(current < limit):(current > limit);
|
||||
return stepp > 0 ? (current < limit) : (current > limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return String.format(Locale.ROOT, "[%s, %s, ..., %s)",NumericValue.of(start).getString(), NumericValue.of(start+stepp).getString(), NumericValue.of( limit).getString());
|
||||
return String.format(Locale.ROOT, "[%s, %s, ..., %s)", NumericValue.of(start).getString(), NumericValue.of(start + stepp).getString(), NumericValue.of(limit).getString());
|
||||
}
|
||||
};
|
||||
}
|
||||
public static LazyListValue rangeLong(long from, long to, long step)
|
||||
|
||||
public static LazyListValue rangeLong(final long from, final long to, final long step)
|
||||
{
|
||||
return new LazyListValue()
|
||||
{
|
||||
{
|
||||
if (step == 0)
|
||||
{
|
||||
throw new InternalExpressionException("Range will never end with a zero step");
|
||||
}
|
||||
this.start = from;
|
||||
this.current = this.start;
|
||||
this.limit = to;
|
||||
this.stepp = step;
|
||||
}
|
||||
|
||||
private final long start;
|
||||
private long current;
|
||||
private final long limit;
|
||||
private final long stepp;
|
||||
|
||||
@Override
|
||||
public Value next()
|
||||
{
|
||||
Value val = new NumericValue(current);
|
||||
final Value val = new NumericValue(current);
|
||||
current += stepp;
|
||||
return val;
|
||||
}
|
||||
@@ -86,13 +97,13 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return stepp > 0?(current < limit):(current > limit);
|
||||
return stepp > 0 ? (current < limit) : (current > limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return String.format(Locale.ROOT, "[%s, %s, ..., %s)",NumericValue.of(start).getString(), NumericValue.of(start+stepp).getString(), NumericValue.of( limit).getString());
|
||||
return String.format(Locale.ROOT, "[%s, %s, ..., %s)", NumericValue.of(start).getString(), NumericValue.of(start + stepp).getString(), NumericValue.of(limit).getString());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -108,20 +119,24 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
|
||||
{
|
||||
return hasNext();
|
||||
}
|
||||
@Override public abstract boolean hasNext();
|
||||
|
||||
@Override public abstract Value next();
|
||||
|
||||
@Override
|
||||
public void fatality() {reset();}
|
||||
public void fatality()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
public abstract void reset();
|
||||
|
||||
@Override
|
||||
public Iterator<Value> iterator() {return this;}
|
||||
public Iterator<Value> iterator()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Value> unroll()
|
||||
{
|
||||
List<Value> result = new ArrayList<>();
|
||||
final List<Value> result = new ArrayList<>();
|
||||
this.forEachRemaining(result::add);
|
||||
fatality();
|
||||
return result;
|
||||
@@ -130,26 +145,38 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
|
||||
@Override
|
||||
public Value slice(long from, Long to)
|
||||
{
|
||||
if (to == null || to < 0) to = (long) Integer.MAX_VALUE;
|
||||
if (from < 0) from = 0;
|
||||
if (to == null || to < 0)
|
||||
{
|
||||
to = (long) Integer.MAX_VALUE;
|
||||
}
|
||||
if (from < 0)
|
||||
{
|
||||
from = 0;
|
||||
}
|
||||
if (from > to)
|
||||
{
|
||||
return ListValue.of();
|
||||
List<Value> result = new ArrayList<>();
|
||||
}
|
||||
final List<Value> result = new ArrayList<>();
|
||||
int i;
|
||||
for (i = 0; i < from; i++)
|
||||
{
|
||||
if (hasNext())
|
||||
{
|
||||
next();
|
||||
}
|
||||
else
|
||||
{
|
||||
fatality();
|
||||
return ListValue.wrap(result);
|
||||
}
|
||||
}
|
||||
for (i = (int)from; i < to; i++)
|
||||
for (i = (int) from; i < to; i++)
|
||||
{
|
||||
if (hasNext())
|
||||
{
|
||||
result.add(next());
|
||||
}
|
||||
else
|
||||
{
|
||||
fatality();
|
||||
@@ -158,8 +185,9 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
|
||||
}
|
||||
return ListValue.wrap(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value add(Value other)
|
||||
public Value add(final Value other)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot add to iterators");
|
||||
}
|
||||
@@ -175,37 +203,42 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
|
||||
{
|
||||
return "iterator";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone()
|
||||
{
|
||||
Object copy;
|
||||
final Object copy;
|
||||
try
|
||||
{
|
||||
copy = super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
catch (final CloneNotSupportedException e)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot copy iterators");
|
||||
}
|
||||
((LazyListValue)copy).reset();
|
||||
((LazyListValue) copy).reset();
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value fromConstant() {
|
||||
return (Value)clone();
|
||||
public Value fromConstant()
|
||||
{
|
||||
return (Value) clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return ("i"+getString()).hashCode();
|
||||
return ("i" + getString()).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
if (!force)
|
||||
{
|
||||
throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
}
|
||||
return StringTag.valueOf(getString());
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import carpet.script.LazyValue;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -14,6 +15,7 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.DoubleTag;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
@@ -28,23 +30,24 @@ import static java.lang.Math.abs;
|
||||
public class ListValue extends AbstractListValue implements ContainerValueInterface
|
||||
{
|
||||
protected final List<Value> items;
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return "["+items.stream().map(Value::getString).collect(Collectors.joining(", "))+"]";
|
||||
return "[" + items.stream().map(Value::getString).collect(Collectors.joining(", ")) + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrettyString()
|
||||
{
|
||||
if (items.size()<8)
|
||||
return "["+items.stream().map(Value::getPrettyString).collect(Collectors.joining(", "))+"]";
|
||||
return "["+items.get(0).getPrettyString()+", "+items.get(1).getPrettyString()+", ..., "+
|
||||
items.get(items.size()-2).getPrettyString()+", "+items.get(items.size()-1).getPrettyString()+"]";
|
||||
return items.size() < 8
|
||||
? "[" + items.stream().map(Value::getPrettyString).collect(Collectors.joining(", ")) + "]"
|
||||
: "[" + items.get(0).getPrettyString() + ", " + items.get(1).getPrettyString() + ", ..., " + items.get(items.size() - 2).getPrettyString() + ", " + items.get(items.size() - 1).getPrettyString() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean() {
|
||||
public boolean getBoolean()
|
||||
{
|
||||
return !items.isEmpty();
|
||||
}
|
||||
|
||||
@@ -57,56 +60,63 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
@Override
|
||||
public Value deepcopy()
|
||||
{
|
||||
List<Value> copyItems = new ArrayList<>(items.size());
|
||||
for (Value entry: items) copyItems.add(entry.deepcopy());
|
||||
final List<Value> copyItems = new ArrayList<>(items.size());
|
||||
for (final Value entry : items)
|
||||
{
|
||||
copyItems.add(entry.deepcopy());
|
||||
}
|
||||
return new ListValue(copyItems);
|
||||
}
|
||||
|
||||
public ListValue(Collection<? extends Value> list)
|
||||
public ListValue(final Collection<? extends Value> list)
|
||||
{
|
||||
items = new ArrayList<>(list);
|
||||
}
|
||||
|
||||
protected ListValue(List<Value> list)
|
||||
protected ListValue(final List<Value> list)
|
||||
{
|
||||
items = list;
|
||||
}
|
||||
|
||||
public static Value fromTriple(double a, double b, double c)
|
||||
public static Value fromTriple(final double a, final double b, final double c)
|
||||
{
|
||||
return ListValue.of(new NumericValue(a), new NumericValue(b), new NumericValue(c));
|
||||
}
|
||||
|
||||
public static Value fromTriple(int a, int b, int c)
|
||||
public static Value fromTriple(final int a, final int b, final int c)
|
||||
{
|
||||
return fromTriple((double) a, b, c);
|
||||
}
|
||||
|
||||
|
||||
public static ListValue wrap(Stream<Value> stream)
|
||||
public static ListValue wrap(final Stream<Value> stream)
|
||||
{
|
||||
return wrap(stream.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public static ListValue wrap(List<Value> list)
|
||||
public static ListValue wrap(final List<Value> list)
|
||||
{
|
||||
return new ListValue(list);
|
||||
}
|
||||
public static ListValue of(Value ... list)
|
||||
|
||||
public static ListValue of(final Value... list)
|
||||
{
|
||||
return new ListValue(new ArrayList<>(Arrays.asList(list)));
|
||||
}
|
||||
public static ListValue ofNums(Number ... list)
|
||||
|
||||
public static ListValue ofNums(final Number... list)
|
||||
{
|
||||
List<Value> valList = new ArrayList<>();
|
||||
for (Number i : list)
|
||||
final List<Value> valList = new ArrayList<>();
|
||||
for (final Number i : list)
|
||||
{
|
||||
valList.add(new NumericValue(i.doubleValue()));
|
||||
}
|
||||
return new ListValue(valList);
|
||||
}
|
||||
|
||||
public static LazyValue lazyEmpty()
|
||||
{
|
||||
Value ret = new ListValue();
|
||||
final Value ret = new ListValue();
|
||||
return (c, t) -> ret;
|
||||
}
|
||||
|
||||
@@ -116,16 +126,17 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value add(Value other) {
|
||||
ListValue output = new ListValue();
|
||||
if (other instanceof ListValue)
|
||||
public Value add(final Value other)
|
||||
{
|
||||
final ListValue output = new ListValue();
|
||||
if (other instanceof final ListValue list)
|
||||
{
|
||||
List<Value> other_list = ((ListValue) other).items;
|
||||
if (other_list.size() == items.size())
|
||||
final List<Value> otherItems = list.items;
|
||||
if (otherItems.size() == items.size())
|
||||
{
|
||||
for(int i = 0, size = items.size(); i < size; i++)
|
||||
for (int i = 0, size = items.size(); i < size; i++)
|
||||
{
|
||||
output.items.add(items.get(i).add(other_list.get(i)));
|
||||
output.items.add(items.get(i).add(otherItems.get(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -135,31 +146,32 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Value v : items)
|
||||
for (final Value v : items)
|
||||
{
|
||||
output.items.add(v.add(other));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void append(Value v)
|
||||
public void append(final Value v)
|
||||
{
|
||||
items.add(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value subtract(Value other)
|
||||
public Value subtract(final Value other)
|
||||
{
|
||||
ListValue output = new ListValue();
|
||||
if (other instanceof ListValue)
|
||||
final ListValue output = new ListValue();
|
||||
if (other instanceof final ListValue list)
|
||||
{
|
||||
List<Value> other_list = ((ListValue) other).items;
|
||||
if (other_list.size() == items.size())
|
||||
final List<Value> otherItems = list.items;
|
||||
if (otherItems.size() == items.size())
|
||||
{
|
||||
for(int i = 0, size = items.size(); i < size; i++)
|
||||
for (int i = 0, size = items.size(); i < size; i++)
|
||||
{
|
||||
output.items.add(items.get(i).subtract(other_list.get(i)));
|
||||
output.items.add(items.get(i).subtract(otherItems.get(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -169,31 +181,32 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Value v : items)
|
||||
for (final Value v : items)
|
||||
{
|
||||
output.items.add(v.subtract(other));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
public void subtractFrom(Value v) // if I ever do -= then it wouod remove items
|
||||
|
||||
public void subtractFrom(final Value v) // if I ever do -= then it wouod remove items
|
||||
{
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Value multiply(Value other)
|
||||
public Value multiply(final Value other)
|
||||
{
|
||||
ListValue output = new ListValue();
|
||||
if (other instanceof ListValue)
|
||||
final ListValue output = new ListValue();
|
||||
if (other instanceof final ListValue list)
|
||||
{
|
||||
List<Value> other_list = ((ListValue) other).items;
|
||||
if (other_list.size() == items.size())
|
||||
final List<Value> otherItems = list.items;
|
||||
if (otherItems.size() == items.size())
|
||||
{
|
||||
for(int i = 0, size = items.size(); i < size; i++)
|
||||
for (int i = 0, size = items.size(); i < size; i++)
|
||||
{
|
||||
output.items.add(items.get(i).multiply(other_list.get(i)));
|
||||
output.items.add(items.get(i).multiply(otherItems.get(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -203,7 +216,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Value v : items)
|
||||
for (final Value v : items)
|
||||
{
|
||||
output.items.add(v.multiply(other));
|
||||
}
|
||||
@@ -212,17 +225,17 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value divide(Value other)
|
||||
public Value divide(final Value other)
|
||||
{
|
||||
ListValue output = new ListValue();
|
||||
if (other instanceof ListValue)
|
||||
final ListValue output = new ListValue();
|
||||
if (other instanceof final ListValue list)
|
||||
{
|
||||
List<Value> other_list = ((ListValue) other).items;
|
||||
if (other_list.size() == items.size())
|
||||
final List<Value> otherItems = list.items;
|
||||
if (otherItems.size() == items.size())
|
||||
{
|
||||
for(int i = 0, size = items.size(); i < size; i++)
|
||||
for (int i = 0, size = items.size(); i < size; i++)
|
||||
{
|
||||
output.items.add(items.get(i).divide(other_list.get(i)));
|
||||
output.items.add(items.get(i).divide(otherItems.get(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -232,7 +245,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Value v : items)
|
||||
for (final Value v : items)
|
||||
{
|
||||
output.items.add(v.divide(other));
|
||||
}
|
||||
@@ -241,19 +254,27 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Value o)
|
||||
public int compareTo(final Value o)
|
||||
{
|
||||
if (o instanceof ListValue)
|
||||
if (o instanceof final ListValue ol)
|
||||
{
|
||||
ListValue ol = (ListValue)o;
|
||||
int this_size = this.getItems().size();
|
||||
int o_size = ol.getItems().size();
|
||||
if (this_size != o_size) return this_size - o_size;
|
||||
if (this_size == 0) return 0;
|
||||
for (int i = 0; i < this_size; i++)
|
||||
final int size = this.getItems().size();
|
||||
final int otherSize = ol.getItems().size();
|
||||
if (size != otherSize)
|
||||
{
|
||||
int res = this.items.get(i).compareTo(ol.items.get(i));
|
||||
if (res != 0) return res;
|
||||
return size - otherSize;
|
||||
}
|
||||
if (size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
final int res = this.items.get(i).compareTo(ol.items.get(i));
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -263,11 +284,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
@Override
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (o instanceof ListValue)
|
||||
{
|
||||
return getItems().equals(((ListValue) o).getItems());
|
||||
}
|
||||
return false;
|
||||
return o instanceof final ListValue list && getItems().equals(list.getItems());
|
||||
}
|
||||
|
||||
public List<Value> getItems()
|
||||
@@ -276,7 +293,10 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Value> iterator() { return new ArrayList<>(items).iterator(); } // should be thread safe
|
||||
public Iterator<Value> iterator()
|
||||
{
|
||||
return new ArrayList<>(items).iterator();
|
||||
} // should be thread safe
|
||||
|
||||
@Override
|
||||
public List<Value> unpack()
|
||||
@@ -284,7 +304,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
return new ArrayList<>(items);
|
||||
}
|
||||
|
||||
public void extend(List<Value> subList)
|
||||
public void extend(final List<Value> subList)
|
||||
{
|
||||
items.addAll(subList);
|
||||
}
|
||||
@@ -296,18 +316,21 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
* @param len
|
||||
* @return
|
||||
*/
|
||||
public static int normalizeIndex(long idx, int len)
|
||||
public static int normalizeIndex(long idx, final int len)
|
||||
{
|
||||
if (idx >=0 && idx < len) return (int)idx;
|
||||
long range = abs(idx)/len;
|
||||
idx += (range+2)*len;
|
||||
if (idx >= 0 && idx < len)
|
||||
{
|
||||
return (int) idx;
|
||||
}
|
||||
final long range = abs(idx) / len;
|
||||
idx += (range + 2) * len;
|
||||
idx = idx % len;
|
||||
return (int)idx;
|
||||
return (int) idx;
|
||||
}
|
||||
|
||||
public static class ListConstructorValue extends ListValue
|
||||
{
|
||||
public ListConstructorValue(Collection<? extends Value> list)
|
||||
public ListConstructorValue(final Collection<? extends Value> list)
|
||||
{
|
||||
super(list);
|
||||
}
|
||||
@@ -320,11 +343,11 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value in(Value value1)
|
||||
public Value in(final Value value1)
|
||||
{
|
||||
for (int i = 0; i < items.size(); i++)
|
||||
{
|
||||
Value v = items.get(i);
|
||||
final Value v = items.get(i);
|
||||
if (v.equals(value1))
|
||||
{
|
||||
return new NumericValue(i);
|
||||
@@ -334,22 +357,27 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value slice(long fromDesc, Long toDesc)
|
||||
public Value slice(final long fromDesc, final Long toDesc)
|
||||
{
|
||||
List<Value> items = getItems();
|
||||
int size = items.size();
|
||||
int from = normalizeIndex(fromDesc, size);
|
||||
final List<Value> items = getItems();
|
||||
final int size = items.size();
|
||||
final int from = normalizeIndex(fromDesc, size);
|
||||
if (toDesc == null)
|
||||
{
|
||||
return new ListValue(new ArrayList<>(getItems().subList(from, size)));
|
||||
int to = normalizeIndex(toDesc, size+1);
|
||||
}
|
||||
final int to = normalizeIndex(toDesc, size + 1);
|
||||
if (from > to)
|
||||
{
|
||||
return ListValue.of();
|
||||
}
|
||||
return new ListValue(new ArrayList<>(getItems().subList(from, to)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value split(Value delimiter) {
|
||||
ListValue result = new ListValue();
|
||||
public Value split(final Value delimiter)
|
||||
{
|
||||
final ListValue result = new ListValue();
|
||||
if (delimiter == null)
|
||||
{
|
||||
this.forEach(item -> result.items.add(of(item)));
|
||||
@@ -357,12 +385,12 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
int startIndex = 0;
|
||||
int index = 0;
|
||||
for (Value val : this.items)
|
||||
for (final Value val : this.items)
|
||||
{
|
||||
index++;
|
||||
if (val.equals(delimiter))
|
||||
{
|
||||
result.items.add(new ListValue(new ArrayList<>(this.items.subList(startIndex, index-1))));
|
||||
result.items.add(new ListValue(new ArrayList<>(this.items.subList(startIndex, index - 1))));
|
||||
startIndex = index;
|
||||
}
|
||||
}
|
||||
@@ -373,35 +401,41 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
@Override
|
||||
public double readDoubleNumber()
|
||||
{
|
||||
return (double)items.size();
|
||||
return items.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean put(Value where, Value value, Value conditionValue)
|
||||
public boolean put(final Value where, final Value value, final Value conditionValue)
|
||||
{
|
||||
String condition = conditionValue.getString();
|
||||
final String condition = conditionValue.getString();
|
||||
if (condition.equalsIgnoreCase("insert"))
|
||||
{
|
||||
return put(where, value, false, false);
|
||||
}
|
||||
if (condition.equalsIgnoreCase("extend"))
|
||||
{
|
||||
return put(where, value, false, true);
|
||||
}
|
||||
if (condition.equalsIgnoreCase("replace"))
|
||||
{
|
||||
return put(where, value, true, false);
|
||||
throw new InternalExpressionException("List 'put' modifier could be either 'insert', 'replace', or extend");
|
||||
}
|
||||
throw new InternalExpressionException("List 'put' modifier could be either 'insert', 'replace', or extend");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean put(Value ind, Value value)
|
||||
public boolean put(final Value ind, final Value value)
|
||||
{
|
||||
return put(ind, value, true, false);
|
||||
}
|
||||
|
||||
private boolean put(Value ind, Value value, boolean replace, boolean extend)
|
||||
private boolean put(final Value ind, final Value value, final boolean replace, final boolean extend)
|
||||
{
|
||||
if (ind.isNull())
|
||||
{
|
||||
if (extend && value instanceof AbstractListValue)
|
||||
{
|
||||
((AbstractListValue) value).iterator().forEachRemaining((v)-> items.add(v));
|
||||
((AbstractListValue) value).iterator().forEachRemaining(items::add);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -410,27 +444,35 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
else
|
||||
{
|
||||
int numitems = items.size();
|
||||
final int numitems = items.size();
|
||||
if (!(ind instanceof NumericValue))
|
||||
{
|
||||
return false;
|
||||
int index = (int)((NumericValue) ind).getLong();
|
||||
}
|
||||
int index = (int) ((NumericValue) ind).getLong();
|
||||
if (index < 0)
|
||||
{// only for values < 0
|
||||
index = normalizeIndex(index, numitems);
|
||||
}
|
||||
if (replace)
|
||||
{
|
||||
while (index >= items.size()) items.add(Value.NULL);
|
||||
while (index >= items.size())
|
||||
{
|
||||
items.add(Value.NULL);
|
||||
}
|
||||
items.set(index, value);
|
||||
return true;
|
||||
}
|
||||
while (index > items.size()) items.add(Value.NULL);
|
||||
while (index > items.size())
|
||||
{
|
||||
items.add(Value.NULL);
|
||||
}
|
||||
|
||||
if (extend && value instanceof AbstractListValue)
|
||||
{
|
||||
Iterable<Value> iterable = ((AbstractListValue) value)::iterator;
|
||||
List<Value> appendix = StreamSupport.stream( iterable.spliterator(), false).collect(Collectors.toList());
|
||||
items.addAll(index, appendix );
|
||||
final Iterable<Value> iterable = ((AbstractListValue) value)::iterator;
|
||||
final List<Value> appendix = StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
|
||||
items.addAll(index, appendix);
|
||||
return true;
|
||||
}
|
||||
items.add(index, value);
|
||||
@@ -439,25 +481,27 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value get(Value value)
|
||||
public Value get(final Value value)
|
||||
{
|
||||
int size = items.size();
|
||||
if (size == 0) return Value.NULL;
|
||||
return items.get(normalizeIndex(NumericValue.asNumber(value, "'address' to a list index").getLong(), size));
|
||||
final int size = items.size();
|
||||
return size == 0 ? Value.NULL : items.get(normalizeIndex(NumericValue.asNumber(value, "'address' to a list index").getLong(), size));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(Value where)
|
||||
public boolean has(final Value where)
|
||||
{
|
||||
long index = NumericValue.asNumber(where, "'address' to a list index").getLong();
|
||||
final long index = NumericValue.asNumber(where, "'address' to a list index").getLong();
|
||||
return index >= 0 && index < items.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(Value where)
|
||||
public boolean delete(final Value where)
|
||||
{
|
||||
if (!(where instanceof NumericValue) || items.isEmpty()) return false;
|
||||
long index = ((NumericValue) where).getLong();
|
||||
if (!(where instanceof NumericValue) || items.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final long index = ((NumericValue) where).getLong();
|
||||
items.remove(normalizeIndex(index, items.size()));
|
||||
return true;
|
||||
}
|
||||
@@ -482,35 +526,54 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
LIST,
|
||||
MAP,
|
||||
STRING;
|
||||
private static TagTypeCompat getType(Tag tag)
|
||||
|
||||
private static TagTypeCompat getType(final Tag tag)
|
||||
{
|
||||
if (tag instanceof IntTag) return INT;
|
||||
if (tag instanceof LongTag) return LONG;
|
||||
if (tag instanceof DoubleTag) return DBL;
|
||||
if (tag instanceof ListTag) return LIST;
|
||||
if (tag instanceof CompoundTag) return MAP;
|
||||
if (tag instanceof IntTag)
|
||||
{
|
||||
return INT;
|
||||
}
|
||||
if (tag instanceof LongTag)
|
||||
{
|
||||
return LONG;
|
||||
}
|
||||
if (tag instanceof DoubleTag)
|
||||
{
|
||||
return DBL;
|
||||
}
|
||||
if (tag instanceof ListTag)
|
||||
{
|
||||
return LIST;
|
||||
}
|
||||
if (tag instanceof CompoundTag)
|
||||
{
|
||||
return MAP;
|
||||
}
|
||||
return STRING;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
int argSize = items.size();
|
||||
if (argSize == 0) return new ListTag();
|
||||
ListTag tag = new ListTag();
|
||||
if (argSize ==1)
|
||||
final int argSize = items.size();
|
||||
if (argSize == 0)
|
||||
{
|
||||
return new ListTag();
|
||||
}
|
||||
final ListTag tag = new ListTag();
|
||||
if (argSize == 1)
|
||||
{
|
||||
tag.add(items.get(0).toTag(force));
|
||||
return tag;
|
||||
}
|
||||
// figuring out the types
|
||||
List<Tag> tags= new ArrayList<>();
|
||||
final List<Tag> tags = new ArrayList<>();
|
||||
items.forEach(v -> tags.add(v.toTag(force)));
|
||||
Set<TagTypeCompat> cases = EnumSet.noneOf(TagTypeCompat.class);
|
||||
final Set<TagTypeCompat> cases = EnumSet.noneOf(TagTypeCompat.class);
|
||||
tags.forEach(t -> cases.add(TagTypeCompat.getType(t)));
|
||||
if (cases.size()==1) // well, one type of items
|
||||
if (cases.size() == 1) // well, one type of items
|
||||
{
|
||||
tag.addAll(tags);
|
||||
return tag;
|
||||
@@ -519,28 +582,28 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
|| cases.contains(TagTypeCompat.MAP)
|
||||
|| cases.contains(TagTypeCompat.STRING)) // incompatible types
|
||||
{
|
||||
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
if (!force)
|
||||
{
|
||||
throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
}
|
||||
tags.forEach(t -> tag.add(StringTag.valueOf(t.getAsString())));
|
||||
return tag;
|
||||
}
|
||||
// only numbers / mixed types
|
||||
if (cases.contains(TagTypeCompat.DBL))
|
||||
{
|
||||
tags.forEach(t -> tag.add(DoubleTag.valueOf(((NumericTag)t).getAsDouble())));
|
||||
}
|
||||
else
|
||||
{
|
||||
tags.forEach(t -> tag.add(LongTag.valueOf(((NumericTag)t).getAsLong())));
|
||||
}
|
||||
tags.forEach(cases.contains(TagTypeCompat.DBL)
|
||||
? (t -> tag.add(DoubleTag.valueOf(((NumericTag) t).getAsDouble())))
|
||||
: (t -> tag.add(LongTag.valueOf(((NumericTag) t).getAsLong()))));
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement toJson()
|
||||
{
|
||||
JsonArray array = new JsonArray();
|
||||
for (Value el: items)
|
||||
final JsonArray array = new JsonArray();
|
||||
for (final Value el : items)
|
||||
{
|
||||
array.add(el.toJson());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package carpet.script.value;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -11,6 +12,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
|
||||
@@ -23,22 +25,16 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
map = new HashMap<>();
|
||||
}
|
||||
|
||||
public MapValue(List<Value> kvPairs)
|
||||
public MapValue(final List<Value> kvPairs)
|
||||
{
|
||||
this();
|
||||
for (Value v : kvPairs)
|
||||
{
|
||||
put(v);
|
||||
}
|
||||
kvPairs.forEach(this::put);
|
||||
}
|
||||
|
||||
public MapValue(Set<Value> keySet)
|
||||
public MapValue(final Set<Value> keySet)
|
||||
{
|
||||
this();
|
||||
for (Value v : keySet)
|
||||
{
|
||||
map.put(v, Value.NULL);
|
||||
}
|
||||
keySet.forEach(v -> map.put(v, Value.NULL));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,20 +52,22 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return "{"+map.entrySet().stream().map((p) -> p.getKey().getString()+": "+p.getValue().getString()).collect(Collectors.joining(", "))+"}";
|
||||
return "{" + map.entrySet().stream().map(p -> p.getKey().getString() + ": " + p.getValue().getString()).collect(Collectors.joining(", ")) + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrettyString()
|
||||
{
|
||||
if (map.size()<6)
|
||||
return "{"+map.entrySet().stream().map((p) -> p.getKey().getPrettyString()+": "+p.getValue().getPrettyString()).collect(Collectors.joining(", "))+"}";
|
||||
List<Value> keys = new ArrayList<>(map.keySet());
|
||||
int max = keys.size();
|
||||
return "{"+keys.get(0).getPrettyString()+": "+map.get(keys.get(0)).getPrettyString()+", "+
|
||||
keys.get(1).getPrettyString()+": "+map.get(keys.get(1)).getPrettyString()+", ..., "+
|
||||
keys.get(max-2).getPrettyString()+": "+map.get(keys.get(max-2)).getPrettyString()+", "+
|
||||
keys.get(max-1).getPrettyString()+": "+map.get(keys.get(max-1)).getPrettyString()+"}";
|
||||
if (map.size() < 6)
|
||||
{
|
||||
return "{" + map.entrySet().stream().map(p -> p.getKey().getPrettyString() + ": " + p.getValue().getPrettyString()).collect(Collectors.joining(", ")) + "}";
|
||||
}
|
||||
final List<Value> keys = new ArrayList<>(map.keySet());
|
||||
final int max = keys.size();
|
||||
return "{" + keys.get(0).getPrettyString() + ": " + map.get(keys.get(0)).getPrettyString() + ", " +
|
||||
keys.get(1).getPrettyString() + ": " + map.get(keys.get(1)).getPrettyString() + ", ..., " +
|
||||
keys.get(max - 2).getPrettyString() + ": " + map.get(keys.get(max - 2)).getPrettyString() + ", " +
|
||||
keys.get(max - 1).getPrettyString() + ": " + map.get(keys.get(max - 1)).getPrettyString() + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,35 +85,34 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
@Override
|
||||
public Value deepcopy()
|
||||
{
|
||||
Map<Value, Value> copyMap = new HashMap<>();
|
||||
final Map<Value, Value> copyMap = new HashMap<>();
|
||||
map.forEach((key, value) -> copyMap.put(key.deepcopy(), value.deepcopy()));
|
||||
return new MapValue(copyMap);
|
||||
}
|
||||
|
||||
private MapValue(Map<Value,Value> other)
|
||||
private MapValue(final Map<Value, Value> other)
|
||||
{
|
||||
map = other;
|
||||
}
|
||||
|
||||
public static MapValue wrap(Map<Value,Value> other)
|
||||
public static MapValue wrap(final Map<Value, Value> other)
|
||||
{
|
||||
return new MapValue(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value add(Value o)
|
||||
public Value add(final Value o)
|
||||
{
|
||||
Map<Value, Value> newItems = new HashMap<>(map);
|
||||
if (o instanceof MapValue)
|
||||
final Map<Value, Value> newItems = new HashMap<>(map);
|
||||
if (o instanceof final MapValue mapValue)
|
||||
{
|
||||
newItems.putAll(((MapValue) o).map);
|
||||
newItems.putAll(mapValue.map);
|
||||
}
|
||||
else if (o instanceof AbstractListValue)
|
||||
else if (o instanceof final AbstractListValue alv)
|
||||
{
|
||||
Iterator<Value> it = ((AbstractListValue) o).iterator();
|
||||
while (it.hasNext())
|
||||
for (final Value value : alv)
|
||||
{
|
||||
newItems.put(it.next(), Value.NULL);
|
||||
newItems.put(value, Value.NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -126,31 +123,30 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value subtract(Value v)
|
||||
public Value subtract(final Value v)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot subtract from a map value");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value multiply(Value v)
|
||||
public Value multiply(final Value v)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot multiply with a map value");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value divide(Value v)
|
||||
public Value divide(final Value v)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot divide a map value");
|
||||
}
|
||||
|
||||
public void put(Value v)
|
||||
public void put(final Value v)
|
||||
{
|
||||
if (!(v instanceof ListValue))
|
||||
if (!(v instanceof final ListValue pair))
|
||||
{
|
||||
map.put(v, Value.NULL);
|
||||
return;
|
||||
}
|
||||
ListValue pair = (ListValue)v;
|
||||
if (pair.getItems().size() != 2)
|
||||
{
|
||||
throw new InternalExpressionException("Map constructor requires elements that have two items");
|
||||
@@ -159,13 +155,13 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
}
|
||||
|
||||
@Override
|
||||
public void append(Value v)
|
||||
public void append(final Value v)
|
||||
{
|
||||
map.put(v, Value.NULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Value o)
|
||||
public int compareTo(final Value o)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot compare with a map value");
|
||||
}
|
||||
@@ -173,11 +169,7 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
@Override
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (o instanceof MapValue)
|
||||
{
|
||||
return map.equals(((MapValue) o).map);
|
||||
}
|
||||
return false;
|
||||
return o instanceof final MapValue mapValue && map.equals(mapValue.map);
|
||||
}
|
||||
|
||||
public Map<Value, Value> getMap()
|
||||
@@ -185,9 +177,9 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
return map;
|
||||
}
|
||||
|
||||
public void extend(List<Value> subList)
|
||||
public void extend(final List<Value> subList)
|
||||
{
|
||||
for (Value v: subList) put(v);
|
||||
subList.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,53 +189,51 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value in(Value value1)
|
||||
public Value in(final Value value)
|
||||
{
|
||||
if (map.containsKey(value1)) return value1;
|
||||
return Value.NULL;
|
||||
return map.containsKey(value) ? value : Value.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value slice(long from, Long to)
|
||||
public Value slice(final long from, final Long to)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot slice a map value");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value split(Value delimiter) {
|
||||
throw new InternalExpressionException("Cannot split a map value");
|
||||
public Value split(final Value delimiter)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot split a map value");
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDoubleNumber()
|
||||
{
|
||||
return (double)map.size();
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value get(Value v2)
|
||||
public Value get(final Value v2)
|
||||
{
|
||||
return map.getOrDefault(v2, Value.NULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(Value where)
|
||||
public boolean has(final Value where)
|
||||
{
|
||||
return map.containsKey(where);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(Value where)
|
||||
public boolean delete(final Value where)
|
||||
{
|
||||
Value ret = map.remove(where);
|
||||
return ret != null;
|
||||
return map.remove(where) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean put(Value key, Value value)
|
||||
public boolean put(final Value key, final Value value)
|
||||
{
|
||||
Value ret = map.put(key, value);
|
||||
return ret != null;
|
||||
return map.put(key, value) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -259,12 +249,15 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
CompoundTag tag = new CompoundTag() ;
|
||||
map.forEach( (k, v) ->
|
||||
final CompoundTag tag = new CompoundTag();
|
||||
map.forEach((k, v) ->
|
||||
{
|
||||
if (!force && !(k instanceof StringValue)) throw new NBTSerializableValue.IncompatibleTypeException(k);
|
||||
if (!force && !(k instanceof StringValue))
|
||||
{
|
||||
throw new NBTSerializableValue.IncompatibleTypeException(k);
|
||||
}
|
||||
tag.put(k.getString(), v.toTag(force));
|
||||
});
|
||||
return tag;
|
||||
@@ -273,10 +266,10 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
@Override
|
||||
public JsonElement toJson()
|
||||
{
|
||||
JsonObject jsonMap = new JsonObject();
|
||||
List<Value> keys = new ArrayList<>(map.keySet());
|
||||
final JsonObject jsonMap = new JsonObject();
|
||||
final List<Value> keys = new ArrayList<>(map.keySet());
|
||||
Collections.sort(keys);
|
||||
keys.forEach( k -> jsonMap.add(k.getString(), map.get(k).toJson()));
|
||||
keys.forEach(k -> jsonMap.add(k.getString(), map.get(k).toJson()));
|
||||
return jsonMap;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import carpet.script.exception.Throwables;
|
||||
import carpet.script.utils.EquipmentInventory;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
@@ -17,6 +18,7 @@ import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.minecraft.commands.arguments.NbtPathArgument;
|
||||
import net.minecraft.commands.arguments.item.ItemInput;
|
||||
import net.minecraft.commands.arguments.item.ItemParser;
|
||||
@@ -59,9 +61,11 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
private Supplier<Tag> nbtSupplier = null;
|
||||
private boolean owned = false;
|
||||
|
||||
private NBTSerializableValue() {}
|
||||
private NBTSerializableValue()
|
||||
{
|
||||
}
|
||||
|
||||
public NBTSerializableValue(String nbtString)
|
||||
public NBTSerializableValue(final String nbtString)
|
||||
{
|
||||
nbtSupplier = () ->
|
||||
{
|
||||
@@ -69,64 +73,70 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
{
|
||||
return (new TagParser(new StringReader(nbtString))).readValue();
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
catch (final CommandSyntaxException e)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect NBT data: "+nbtString);
|
||||
throw new InternalExpressionException("Incorrect NBT data: " + nbtString);
|
||||
}
|
||||
};
|
||||
owned = true;
|
||||
}
|
||||
|
||||
public NBTSerializableValue(Tag tag)
|
||||
public NBTSerializableValue(final Tag tag)
|
||||
{
|
||||
nbtTag = tag;
|
||||
owned = true;
|
||||
}
|
||||
|
||||
public static Value of(Tag tag)
|
||||
public static Value of(final Tag tag)
|
||||
{
|
||||
if (tag == null) return Value.NULL;
|
||||
if (tag == null)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
return new NBTSerializableValue(tag);
|
||||
}
|
||||
|
||||
public NBTSerializableValue(Supplier<Tag> tagSupplier)
|
||||
public NBTSerializableValue(final Supplier<Tag> tagSupplier)
|
||||
{
|
||||
nbtSupplier = tagSupplier;
|
||||
}
|
||||
|
||||
public static Value fromStack(ItemStack stack)
|
||||
public static Value fromStack(final ItemStack stack)
|
||||
{
|
||||
if (stack.hasTag())
|
||||
{
|
||||
NBTSerializableValue value = new NBTSerializableValue();
|
||||
final NBTSerializableValue value = new NBTSerializableValue();
|
||||
value.nbtSupplier = stack::getTag;
|
||||
return value;
|
||||
}
|
||||
return Value.NULL;
|
||||
}
|
||||
|
||||
public static String nameFromRegistryId(ResourceLocation id)
|
||||
public static String nameFromRegistryId(final ResourceLocation id)
|
||||
{
|
||||
if (id == null) // should be Value.NULL
|
||||
{
|
||||
return "";
|
||||
if (id.getNamespace().equals("minecraft"))
|
||||
return id.getPath();
|
||||
return id.toString();
|
||||
}
|
||||
return id.getNamespace().equals("minecraft") ? id.getPath() : id.toString();
|
||||
}
|
||||
|
||||
public static NBTSerializableValue parseString(String nbtString, boolean fail)
|
||||
public static NBTSerializableValue parseString(final String nbtString, final boolean fail)
|
||||
{
|
||||
Tag tag;
|
||||
final Tag tag;
|
||||
try
|
||||
{
|
||||
tag = (new TagParser(new StringReader(nbtString))).readValue();
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
catch (final CommandSyntaxException e)
|
||||
{
|
||||
if (fail) throw new InternalExpressionException("Incorrect NBT tag: "+ nbtString);
|
||||
if (fail)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect NBT tag: " + nbtString);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
NBTSerializableValue value = new NBTSerializableValue(tag);
|
||||
final NBTSerializableValue value = new NBTSerializableValue(tag);
|
||||
value.nbtString = null;
|
||||
return value;
|
||||
}
|
||||
@@ -136,7 +146,7 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
public Value clone()
|
||||
{
|
||||
// sets only nbttag, even if emtpy;
|
||||
NBTSerializableValue copy = new NBTSerializableValue(nbtTag);
|
||||
final NBTSerializableValue copy = new NBTSerializableValue(nbtTag);
|
||||
copy.nbtSupplier = this.nbtSupplier;
|
||||
copy.nbtString = this.nbtString;
|
||||
copy.owned = this.owned;
|
||||
@@ -146,59 +156,67 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
@Override
|
||||
public Value deepcopy()
|
||||
{
|
||||
NBTSerializableValue copy = (NBTSerializableValue) clone();
|
||||
final NBTSerializableValue copy = (NBTSerializableValue) clone();
|
||||
copy.owned = false;
|
||||
ensureOwnership();
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value fromConstant() {
|
||||
public Value fromConstant()
|
||||
{
|
||||
return deepcopy();
|
||||
}
|
||||
|
||||
// stolen from HopperBlockEntity, adjusted for threaded operation
|
||||
public static Container getInventoryAt(ServerLevel world, BlockPos blockPos)
|
||||
public static Container getInventoryAt(final ServerLevel world, final BlockPos blockPos)
|
||||
{
|
||||
Container inventory = null;
|
||||
BlockState blockState = world.getBlockState(blockPos);
|
||||
Block block = blockState.getBlock();
|
||||
if (block instanceof WorldlyContainerHolder) {
|
||||
inventory = ((WorldlyContainerHolder)block).getContainer(blockState, world, blockPos);
|
||||
} else if (blockState.hasBlockEntity()) {
|
||||
BlockEntity blockEntity = BlockValue.getBlockEntity(world, blockPos);
|
||||
if (blockEntity instanceof Container) {
|
||||
inventory = (Container)blockEntity;
|
||||
if (inventory instanceof ChestBlockEntity && block instanceof ChestBlock) {
|
||||
inventory = ChestBlock.getContainer((ChestBlock)block, blockState, world, blockPos, true);
|
||||
final BlockState blockState = world.getBlockState(blockPos);
|
||||
final Block block = blockState.getBlock();
|
||||
if (block instanceof final WorldlyContainerHolder containerHolder)
|
||||
{
|
||||
inventory = containerHolder.getContainer(blockState, world, blockPos);
|
||||
}
|
||||
else if (blockState.hasBlockEntity())
|
||||
{
|
||||
final BlockEntity blockEntity = BlockValue.getBlockEntity(world, blockPos);
|
||||
if (blockEntity instanceof final Container inventoryHolder)
|
||||
{
|
||||
inventory = inventoryHolder;
|
||||
if (inventory instanceof ChestBlockEntity && block instanceof final ChestBlock chestBlock)
|
||||
{
|
||||
inventory = ChestBlock.getContainer(chestBlock, blockState, world, blockPos, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inventory == null) {
|
||||
List<Entity> list = world.getEntities(
|
||||
(Entity)null, //TODO check this matches the correct method
|
||||
if (inventory == null)
|
||||
{
|
||||
final List<Entity> list = world.getEntities(
|
||||
(Entity) null, //TODO check this matches the correct method
|
||||
new AABB(
|
||||
blockPos.getX() - 0.5D, blockPos.getY() - 0.5D, blockPos.getZ() - 0.5D,
|
||||
blockPos.getX() + 0.5D, blockPos.getY() + 0.5D, blockPos.getZ() + 0.5D),
|
||||
EntitySelector.CONTAINER_ENTITY_SELECTOR
|
||||
);
|
||||
if (!list.isEmpty()) {
|
||||
inventory = (Container)list.get(world.random.nextInt(list.size()));
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
inventory = (Container) list.get(world.random.nextInt(list.size()));
|
||||
}
|
||||
}
|
||||
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public static InventoryLocator locateInventory(CarpetContext c, List<Value> params, int offset)
|
||||
public static InventoryLocator locateInventory(final CarpetContext c, final List<Value> params, int offset)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value v1 = params.get(offset);
|
||||
if (v1.isNull())
|
||||
{
|
||||
offset ++;
|
||||
offset++;
|
||||
v1 = params.get(offset);
|
||||
}
|
||||
else if (v1 instanceof StringValue)
|
||||
@@ -206,23 +224,38 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
String strVal = v1.getString().toLowerCase(Locale.ROOT);
|
||||
if (strVal.equals("enderchest"))
|
||||
{
|
||||
Value v2 = params.get(1 + offset);
|
||||
ServerPlayer player = EntityValue.getPlayerByValue(c.server(), v2);
|
||||
if (player == null) throw new InternalExpressionException("enderchest inventory requires player argument");
|
||||
final Value v2 = params.get(1 + offset);
|
||||
final ServerPlayer player = EntityValue.getPlayerByValue(c.server(), v2);
|
||||
if (player == null)
|
||||
{
|
||||
throw new InternalExpressionException("enderchest inventory requires player argument");
|
||||
}
|
||||
return new InventoryLocator(player, player.blockPosition(), player.getEnderChestInventory(), offset + 2, true);
|
||||
}
|
||||
if (strVal.equals("equipment"))
|
||||
{
|
||||
Value v2 = params.get(1 + offset);
|
||||
if (!(v2 instanceof EntityValue)) throw new InternalExpressionException("Equipment inventory requires a living entity argument");
|
||||
Entity e = ((EntityValue) v2).getEntity();
|
||||
if (!(e instanceof LivingEntity)) throw new InternalExpressionException("Equipment inventory requires a living entity argument");
|
||||
return new InventoryLocator(e, e.blockPosition(), new EquipmentInventory((LivingEntity) e), offset + 2);
|
||||
final Value v2 = params.get(1 + offset);
|
||||
if (!(v2 instanceof final EntityValue ev))
|
||||
{
|
||||
throw new InternalExpressionException("Equipment inventory requires a living entity argument");
|
||||
}
|
||||
final Entity e = ev.getEntity();
|
||||
if (!(e instanceof final LivingEntity le))
|
||||
{
|
||||
throw new InternalExpressionException("Equipment inventory requires a living entity argument");
|
||||
}
|
||||
return new InventoryLocator(e, e.blockPosition(), new EquipmentInventory(le), offset + 2);
|
||||
}
|
||||
final boolean isEnder = strVal.startsWith("enderchest_");
|
||||
if (isEnder)
|
||||
{
|
||||
strVal = strVal.substring(11); // len("enderchest_")
|
||||
}
|
||||
final ServerPlayer player = c.server().getPlayerList().getPlayerByName(strVal);
|
||||
if (player == null)
|
||||
{
|
||||
throw new InternalExpressionException("String description of an inventory should either denote a player or player's enderchest");
|
||||
}
|
||||
boolean isEnder = strVal.startsWith("enderchest_");
|
||||
if (isEnder) strVal = strVal.substring(11); // len("enderchest_")
|
||||
ServerPlayer player = c.server().getPlayerList().getPlayerByName(strVal);
|
||||
if (player == null) throw new InternalExpressionException("String description of an inventory should either denote a player or player's enderchest");
|
||||
return new InventoryLocator(
|
||||
player,
|
||||
player.blockPosition(),
|
||||
@@ -231,149 +264,150 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
isEnder
|
||||
);
|
||||
}
|
||||
if (v1 instanceof EntityValue)
|
||||
if (v1 instanceof final EntityValue ev)
|
||||
{
|
||||
Container inv = null;
|
||||
Entity e = ((EntityValue) v1).getEntity();
|
||||
if (e instanceof Player pe) inv = pe.getInventory();
|
||||
else if (e instanceof Container) inv = (Container) e;
|
||||
else if (e instanceof InventoryCarrier io) inv = io.getInventory();
|
||||
else if (e instanceof InventoryBearerInterface ibi) inv = ibi.getCMInventory(); // horse only
|
||||
else if (e instanceof LivingEntity le) return new InventoryLocator(e, e.blockPosition(), new EquipmentInventory(le), offset+1);
|
||||
if (inv == null)
|
||||
return null;
|
||||
final Entity e = ev.getEntity();
|
||||
if (e instanceof final Player pe)
|
||||
{
|
||||
inv = pe.getInventory();
|
||||
}
|
||||
else if (e instanceof final Container container)
|
||||
{
|
||||
inv = container;
|
||||
}
|
||||
else if (e instanceof final InventoryCarrier io)
|
||||
{
|
||||
inv = io.getInventory();
|
||||
}
|
||||
else if (e instanceof final InventoryBearerInterface ibi)
|
||||
{
|
||||
inv = ibi.getCMInventory(); // horse only
|
||||
}
|
||||
else if (e instanceof final LivingEntity le)
|
||||
{
|
||||
return new InventoryLocator(e, e.blockPosition(), new EquipmentInventory(le), offset + 1);
|
||||
}
|
||||
return inv == null ? null : new InventoryLocator(e, e.blockPosition(), inv, offset + 1);
|
||||
|
||||
return new InventoryLocator(e, e.blockPosition(), inv, offset+1);
|
||||
}
|
||||
if (v1 instanceof BlockValue)
|
||||
if (v1 instanceof final BlockValue bv)
|
||||
{
|
||||
BlockPos pos = ((BlockValue) v1).getPos();
|
||||
final BlockPos pos = bv.getPos();
|
||||
if (pos == null)
|
||||
{
|
||||
throw new InternalExpressionException("Block to access inventory needs to be positioned in the world");
|
||||
Container inv = getInventoryAt(c.level(), pos);
|
||||
if (inv == null)
|
||||
return null;
|
||||
return new InventoryLocator(pos, pos, inv, offset+1);
|
||||
}
|
||||
final Container inv = getInventoryAt(c.level(), pos);
|
||||
return inv == null ? null : new InventoryLocator(pos, pos, inv, offset + 1);
|
||||
}
|
||||
if (v1 instanceof ListValue)
|
||||
if (v1 instanceof final ListValue lv)
|
||||
{
|
||||
List<Value> args = ((ListValue) v1).getItems();
|
||||
BlockPos pos = new BlockPos(
|
||||
final List<Value> args = lv.getItems();
|
||||
final BlockPos pos = new BlockPos(
|
||||
NumericValue.asNumber(args.get(0)).getDouble(),
|
||||
NumericValue.asNumber(args.get(1)).getDouble(),
|
||||
NumericValue.asNumber(args.get(2)).getDouble());
|
||||
Container inv = getInventoryAt(c.level(), pos);
|
||||
if (inv == null)
|
||||
return null;
|
||||
return new InventoryLocator(pos, pos, inv, offset+1);
|
||||
final Container inv = getInventoryAt(c.level(), pos);
|
||||
return inv == null ? null : new InventoryLocator(pos, pos, inv, offset + 1);
|
||||
}
|
||||
if (v1 instanceof ScreenValue screenValue)
|
||||
if (v1 instanceof final ScreenValue screenValue)
|
||||
{
|
||||
if(!screenValue.isOpen()) return null;
|
||||
return new InventoryLocator(screenValue.getPlayer(), screenValue.getPlayer().blockPosition(), screenValue.getInventory(), offset+1);
|
||||
return !screenValue.isOpen() ? null : new InventoryLocator(screenValue.getPlayer(), screenValue.getPlayer().blockPosition(), screenValue.getInventory(), offset + 1);
|
||||
}
|
||||
BlockPos pos = new BlockPos(
|
||||
final BlockPos pos = new BlockPos(
|
||||
NumericValue.asNumber(v1).getDouble(),
|
||||
NumericValue.asNumber(params.get(1 + offset)).getDouble(),
|
||||
NumericValue.asNumber(params.get(2 + offset)).getDouble());
|
||||
Container inv = getInventoryAt(c.level(), pos);
|
||||
if (inv == null)
|
||||
return null;
|
||||
return new InventoryLocator(pos, pos, inv, offset + 3);
|
||||
final Container inv = getInventoryAt(c.level(), pos);
|
||||
return inv == null ? null : new InventoryLocator(pos, pos, inv, offset + 3);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
catch (final IndexOutOfBoundsException e)
|
||||
{
|
||||
throw new InternalExpressionException("Inventory should be defined either by three coordinates, a block value, an entity, or a screen");
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<String,ItemInput> itemCache = new HashMap<>();
|
||||
private static final Map<String, ItemInput> itemCache = new HashMap<>();
|
||||
|
||||
public static ItemInput parseItem(String itemString, RegistryAccess regs)
|
||||
public static ItemInput parseItem(final String itemString, final RegistryAccess regs)
|
||||
{
|
||||
return parseItem(itemString, null, regs);
|
||||
}
|
||||
|
||||
public static ItemInput parseItem(String itemString, CompoundTag customTag, RegistryAccess regs)
|
||||
public static ItemInput parseItem(final String itemString, final CompoundTag customTag, final RegistryAccess regs)
|
||||
{
|
||||
try
|
||||
{
|
||||
ItemInput res = itemCache.get(itemString); // [SCARY SHIT] persistent caches over server reloads
|
||||
if (res != null)
|
||||
if (customTag == null)
|
||||
return res;
|
||||
else
|
||||
return new ItemInput(Holder.direct(res.getItem()), customTag);
|
||||
ItemParser.ItemResult parser = ItemParser.parseForItem(regs.lookupOrThrow(Registries.ITEM), new StringReader(itemString));
|
||||
{
|
||||
return customTag == null ? res : new ItemInput(Holder.direct(res.getItem()), customTag);
|
||||
}
|
||||
final ItemParser.ItemResult parser = ItemParser.parseForItem(regs.lookupOrThrow(Registries.ITEM), new StringReader(itemString));
|
||||
res = new ItemInput(parser.item(), parser.nbt());
|
||||
|
||||
itemCache.put(itemString, res);
|
||||
if (itemCache.size()>64000)
|
||||
if (itemCache.size() > 64000)
|
||||
{
|
||||
itemCache.clear();
|
||||
if (customTag == null)
|
||||
return res;
|
||||
else
|
||||
return new ItemInput(Holder.direct(res.getItem()), customTag);
|
||||
}
|
||||
return customTag == null ? res : new ItemInput(Holder.direct(res.getItem()), customTag);
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
catch (final CommandSyntaxException e)
|
||||
{
|
||||
throw new ThrowStatement(itemString, Throwables.UNKNOWN_ITEM);
|
||||
}
|
||||
}
|
||||
|
||||
public static int validateSlot(int slot, Container inv)
|
||||
public static int validateSlot(int slot, final Container inv)
|
||||
{
|
||||
int invSize = inv.getContainerSize();
|
||||
final int invSize = inv.getContainerSize();
|
||||
if (slot < 0)
|
||||
{
|
||||
slot = invSize + slot;
|
||||
if (slot < 0 || slot >= invSize)
|
||||
return inv.getContainerSize(); // outside of inventory
|
||||
return slot;
|
||||
}
|
||||
return slot < 0 || slot >= invSize ? inv.getContainerSize() : slot; // outside of inventory
|
||||
}
|
||||
|
||||
private static Value decodeSimpleTag(Tag t)
|
||||
private static Value decodeSimpleTag(final Tag t)
|
||||
{
|
||||
if (t instanceof NumericTag)
|
||||
if (t instanceof final NumericTag number)
|
||||
{
|
||||
if (t instanceof LongTag || t instanceof IntTag) // short and byte will never exceed float's precision, even int won't
|
||||
{
|
||||
return NumericValue.of(((NumericTag) t).getAsLong());
|
||||
}
|
||||
return NumericValue.of(((NumericTag) t).getAsNumber());
|
||||
// short and byte will never exceed float's precision, even int won't
|
||||
return t instanceof LongTag || t instanceof IntTag ? NumericValue.of(number.getAsLong()) : NumericValue.of(number.getAsNumber());
|
||||
}
|
||||
if (t instanceof StringTag)
|
||||
return StringValue.of(t.getAsString());
|
||||
if (t instanceof EndTag)
|
||||
return Value.NULL;
|
||||
|
||||
throw new InternalExpressionException("How did we get here: Unknown nbt element class: "+t.getType().getName());
|
||||
|
||||
}
|
||||
|
||||
private static Value decodeTag(Tag t)
|
||||
{
|
||||
if (t instanceof CompoundTag || t instanceof CollectionTag)
|
||||
return new NBTSerializableValue(() -> t);
|
||||
return decodeSimpleTag(t);
|
||||
}
|
||||
|
||||
private static Value decodeTagDeep(Tag t)
|
||||
{
|
||||
if (t instanceof CompoundTag)
|
||||
{
|
||||
Map<Value, Value> pairs = new HashMap<>();
|
||||
CompoundTag ctag = (CompoundTag)t;
|
||||
for (String key: ctag.getAllKeys())
|
||||
return StringValue.of(t.getAsString());
|
||||
}
|
||||
if (t instanceof EndTag)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
throw new InternalExpressionException("How did we get here: Unknown nbt element class: " + t.getType().getName());
|
||||
}
|
||||
|
||||
private static Value decodeTag(final Tag t)
|
||||
{
|
||||
return t instanceof CompoundTag || t instanceof CollectionTag ? new NBTSerializableValue(() -> t) : decodeSimpleTag(t);
|
||||
}
|
||||
|
||||
private static Value decodeTagDeep(final Tag t)
|
||||
{
|
||||
if (t instanceof final CompoundTag ctag)
|
||||
{
|
||||
final Map<Value, Value> pairs = new HashMap<>();
|
||||
for (final String key : ctag.getAllKeys())
|
||||
{
|
||||
pairs.put(new StringValue(key), decodeTagDeep(ctag.get(key)));
|
||||
}
|
||||
return MapValue.wrap(pairs);
|
||||
}
|
||||
if (t instanceof CollectionTag)
|
||||
if (t instanceof final CollectionTag<?> ltag)
|
||||
{
|
||||
List<Value> elems = new ArrayList<>();
|
||||
CollectionTag<?> ltag = (CollectionTag<?>)t;
|
||||
for (Tag elem: ltag)
|
||||
final List<Value> elems = new ArrayList<>();
|
||||
for (final Tag elem : ltag)
|
||||
{
|
||||
elems.add(decodeTagDeep(elem));
|
||||
}
|
||||
@@ -387,50 +421,64 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
return decodeTagDeep(this.getTag());
|
||||
}
|
||||
|
||||
public static Value fromValue(Value v)
|
||||
public static Value fromValue(final Value v)
|
||||
{
|
||||
if (v instanceof NBTSerializableValue)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
if (v.isNull())
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
return NBTSerializableValue.parseString(v.getString(), true);
|
||||
}
|
||||
|
||||
public Tag getTag()
|
||||
{
|
||||
if (nbtTag == null)
|
||||
{
|
||||
nbtTag = nbtSupplier.get();
|
||||
}
|
||||
return nbtTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (o instanceof NBTSerializableValue)
|
||||
return getTag().equals(((NBTSerializableValue) o).getTag());
|
||||
return super.equals(o);
|
||||
return o instanceof final NBTSerializableValue nbtsv ? getTag().equals(nbtsv.getTag()) : super.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
if (nbtString == null)
|
||||
{
|
||||
nbtString = getTag().toString();
|
||||
}
|
||||
return nbtString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean()
|
||||
{
|
||||
Tag tag = getTag();
|
||||
if (tag instanceof CompoundTag)
|
||||
return !((CompoundTag) tag).isEmpty();
|
||||
if (tag instanceof CollectionTag)
|
||||
return !((CollectionTag<?>) tag).isEmpty();
|
||||
if (tag instanceof NumericTag)
|
||||
return ((NumericTag) tag).getAsDouble()!=0.0;
|
||||
final Tag tag = getTag();
|
||||
if (tag instanceof final CompoundTag ctag)
|
||||
{
|
||||
return !(ctag).isEmpty();
|
||||
}
|
||||
if (tag instanceof final CollectionTag<?> ltag)
|
||||
{
|
||||
return !(ltag).isEmpty();
|
||||
}
|
||||
if (tag instanceof final NumericTag number)
|
||||
{
|
||||
return number.getAsDouble() != 0.0;
|
||||
}
|
||||
if (tag instanceof StringTag)
|
||||
{
|
||||
return !tag.getAsString().isEmpty();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -441,86 +489,89 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
ensureOwnership();
|
||||
return (CompoundTag) getTag();
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
catch (final ClassCastException e)
|
||||
{
|
||||
throw new InternalExpressionException(getString()+" is not a valid compound tag");
|
||||
throw new InternalExpressionException(getString() + " is not a valid compound tag");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean put(Value where, Value value)
|
||||
public boolean put(final Value where, final Value value)
|
||||
{
|
||||
return put(where, value, new StringValue("replace"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean put(Value where, Value value, Value conditions)
|
||||
public boolean put(final Value where, final Value value, final Value conditions)
|
||||
{
|
||||
/// WIP
|
||||
ensureOwnership();
|
||||
NbtPathArgument.NbtPath path = cachePath(where.getString());
|
||||
Tag tagToInsert = value instanceof NBTSerializableValue ?
|
||||
((NBTSerializableValue) value).getTag() :
|
||||
new NBTSerializableValue(value.getString()).getTag();
|
||||
boolean modifiedTag;
|
||||
if (conditions instanceof NumericValue)
|
||||
final NbtPathArgument.NbtPath path = cachePath(where.getString());
|
||||
final Tag tagToInsert = value instanceof final NBTSerializableValue nbtsv
|
||||
? nbtsv.getTag()
|
||||
: new NBTSerializableValue(value.getString()).getTag();
|
||||
final boolean modifiedTag;
|
||||
if (conditions instanceof final NumericValue number)
|
||||
{
|
||||
modifiedTag = modify_insert((int)((NumericValue) conditions).getLong(), path, tagToInsert);
|
||||
modifiedTag = modifyInsert((int) number.getLong(), path, tagToInsert);
|
||||
}
|
||||
else
|
||||
{
|
||||
String ops = conditions.getString();
|
||||
final String ops = conditions.getString();
|
||||
if (ops.equalsIgnoreCase("merge"))
|
||||
{
|
||||
modifiedTag = modify_merge(path, tagToInsert);
|
||||
modifiedTag = modifyMerge(path, tagToInsert);
|
||||
}
|
||||
else if (ops.equalsIgnoreCase("replace"))
|
||||
{
|
||||
modifiedTag = modify_replace(path, tagToInsert);
|
||||
modifiedTag = modifyReplace(path, tagToInsert);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (modifiedTag) dirty();
|
||||
if (modifiedTag)
|
||||
{
|
||||
dirty();
|
||||
}
|
||||
return modifiedTag;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private boolean modify_insert(int index, NbtPathArgument.NbtPath nbtPath, Tag newElement)
|
||||
private boolean modifyInsert(final int index, final NbtPathArgument.NbtPath nbtPath, final Tag newElement)
|
||||
{
|
||||
return modify_insert(index, nbtPath, newElement, this.getTag());
|
||||
return modifyInsert(index, nbtPath, newElement, this.getTag());
|
||||
}
|
||||
|
||||
private boolean modify_insert(int index, NbtPathArgument.NbtPath nbtPath, Tag newElement, Tag currentTag)
|
||||
private boolean modifyInsert(final int index, final NbtPathArgument.NbtPath nbtPath, final Tag newElement, final Tag currentTag)
|
||||
{
|
||||
Collection<Tag> targets;
|
||||
final Collection<Tag> targets;
|
||||
try
|
||||
{
|
||||
targets = nbtPath.getOrCreate(currentTag, ListTag::new);
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
catch (final CommandSyntaxException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean modified = false;
|
||||
for (Tag target : targets)
|
||||
for (final Tag target : targets)
|
||||
{
|
||||
if (!(target instanceof CollectionTag))
|
||||
if (!(target instanceof final CollectionTag<?> targetList))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
CollectionTag<?> targetList = (CollectionTag<?>) target;
|
||||
if (!targetList.addTag(index < 0 ? targetList.size() + index + 1 : index, newElement.copy()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
catch (IndexOutOfBoundsException ignored)
|
||||
catch (final IndexOutOfBoundsException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -528,68 +579,72 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
}
|
||||
|
||||
|
||||
private boolean modify_merge(NbtPathArgument.NbtPath nbtPath, Tag replacement) //nbtPathArgumentType$NbtPath_1, list_1)
|
||||
private boolean modifyMerge(final NbtPathArgument.NbtPath nbtPath, final Tag replacement) //nbtPathArgumentType$NbtPath_1, list_1)
|
||||
{
|
||||
if (!(replacement instanceof CompoundTag))
|
||||
if (!(replacement instanceof final CompoundTag replacementCompound))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Tag ownTag = getTag();
|
||||
final Tag ownTag = getTag();
|
||||
try
|
||||
{
|
||||
for (Tag target : nbtPath.getOrCreate(ownTag, CompoundTag::new))
|
||||
for (final Tag target : nbtPath.getOrCreate(ownTag, CompoundTag::new))
|
||||
{
|
||||
if (!(target instanceof CompoundTag))
|
||||
if (!(target instanceof final CompoundTag targetCompound))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
((CompoundTag) target).merge((CompoundTag) replacement);
|
||||
targetCompound.merge(replacementCompound);
|
||||
}
|
||||
}
|
||||
catch (CommandSyntaxException ignored)
|
||||
catch (final CommandSyntaxException ignored)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean modify_replace(NbtPathArgument.NbtPath nbtPath, Tag replacement) //nbtPathArgumentType$NbtPath_1, list_1)
|
||||
private boolean modifyReplace(final NbtPathArgument.NbtPath nbtPath, final Tag replacement) //nbtPathArgumentType$NbtPath_1, list_1)
|
||||
{
|
||||
Tag tag = getTag();
|
||||
String pathText = nbtPath.toString();
|
||||
final Tag tag = getTag();
|
||||
final String pathText = nbtPath.toString();
|
||||
if (pathText.endsWith("]")) // workaround for array replacement or item in the array replacement
|
||||
{
|
||||
if (nbtPath.remove(tag)==0)
|
||||
if (nbtPath.remove(tag) == 0)
|
||||
{
|
||||
return false;
|
||||
Pattern pattern = Pattern.compile("\\[[^\\[]*]$");
|
||||
Matcher matcher = pattern.matcher(pathText);
|
||||
}
|
||||
final Pattern pattern = Pattern.compile("\\[[^\\[]*]$");
|
||||
final Matcher matcher = pattern.matcher(pathText);
|
||||
if (!matcher.find()) // malformed path
|
||||
{
|
||||
return false;
|
||||
}
|
||||
String arrAccess = matcher.group();
|
||||
int pos;
|
||||
if (arrAccess.length()==2) // we just removed entire array
|
||||
final String arrAccess = matcher.group();
|
||||
final int pos;
|
||||
if (arrAccess.length() == 2) // we just removed entire array
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
pos = Integer.parseInt(arrAccess.substring(1, arrAccess.length() - 1));
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
catch (final NumberFormatException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
NbtPathArgument.NbtPath newPath = cachePath(pathText.substring(0, pathText.length()-arrAccess.length()));
|
||||
return modify_insert(pos,newPath,replacement, tag);
|
||||
final NbtPathArgument.NbtPath newPath = cachePath(pathText.substring(0, pathText.length() - arrAccess.length()));
|
||||
return modifyInsert(pos, newPath, replacement, tag);
|
||||
}
|
||||
try
|
||||
{
|
||||
nbtPath.set(tag, replacement);
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
catch (final CommandSyntaxException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -597,25 +652,31 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value get(Value value)
|
||||
public Value get(final Value value)
|
||||
{
|
||||
String valString = value.getString();
|
||||
NbtPathArgument.NbtPath path = cachePath(valString);
|
||||
final String valString = value.getString();
|
||||
final NbtPathArgument.NbtPath path = cachePath(valString);
|
||||
try
|
||||
{
|
||||
List<Tag> tags = path.get(getTag());
|
||||
if (tags.size()==0)
|
||||
final List<Tag> tags = path.get(getTag());
|
||||
if (tags.isEmpty())
|
||||
{
|
||||
return Value.NULL;
|
||||
if (tags.size()==1 && !valString.endsWith("[]"))
|
||||
}
|
||||
if (tags.size() == 1 && !valString.endsWith("[]"))
|
||||
{
|
||||
return NBTSerializableValue.decodeTag(tags.get(0));
|
||||
}
|
||||
return ListValue.wrap(tags.stream().map(NBTSerializableValue::decodeTag));
|
||||
}
|
||||
catch (CommandSyntaxException ignored) { }
|
||||
catch (final CommandSyntaxException ignored)
|
||||
{
|
||||
}
|
||||
return Value.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(Value where)
|
||||
public boolean has(final Value where)
|
||||
{
|
||||
return cachePath(where.getString()).countMatching(getTag()) > 0;
|
||||
}
|
||||
@@ -637,11 +698,11 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(Value where)
|
||||
public boolean delete(final Value where)
|
||||
{
|
||||
NbtPathArgument.NbtPath path = cachePath(where.getString());
|
||||
final NbtPathArgument.NbtPath path = cachePath(where.getString());
|
||||
ensureOwnership();
|
||||
int removed = path.remove(getTag());
|
||||
final int removed = path.remove(getTag());
|
||||
if (removed > 0)
|
||||
{
|
||||
dirty();
|
||||
@@ -650,30 +711,36 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
return false;
|
||||
}
|
||||
|
||||
public static record InventoryLocator(Object owner, BlockPos position, Container inventory, int offset, boolean isEnder)
|
||||
public record InventoryLocator(Object owner, BlockPos position, Container inventory, int offset,
|
||||
boolean isEnder)
|
||||
{
|
||||
InventoryLocator(Object owner, BlockPos pos, Container i, int o)
|
||||
InventoryLocator(final Object owner, final BlockPos pos, final Container i, final int o)
|
||||
{
|
||||
this(owner, pos, i, o, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, NbtPathArgument.NbtPath> pathCache = new HashMap<>();
|
||||
private static NbtPathArgument.NbtPath cachePath(String arg)
|
||||
private static final Map<String, NbtPathArgument.NbtPath> pathCache = new HashMap<>();
|
||||
|
||||
private static NbtPathArgument.NbtPath cachePath(final String arg)
|
||||
{
|
||||
NbtPathArgument.NbtPath res = pathCache.get(arg);
|
||||
if (res != null)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
try
|
||||
{
|
||||
res = NbtPathArgument.nbtPath().parse(new StringReader(arg));
|
||||
}
|
||||
catch (CommandSyntaxException exc)
|
||||
catch (final CommandSyntaxException exc)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect nbt path: "+arg);
|
||||
throw new InternalExpressionException("Incorrect nbt path: " + arg);
|
||||
}
|
||||
if (pathCache.size() > 1024)
|
||||
{
|
||||
pathCache.clear();
|
||||
}
|
||||
pathCache.put(arg, res);
|
||||
return res;
|
||||
}
|
||||
@@ -686,9 +753,12 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
if (!force)
|
||||
{
|
||||
throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
}
|
||||
ensureOwnership();
|
||||
return getTag();
|
||||
}
|
||||
@@ -696,9 +766,11 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
public static class IncompatibleTypeException extends RuntimeException
|
||||
{
|
||||
public final Value val;
|
||||
public IncompatibleTypeException(Value val)
|
||||
|
||||
public IncompatibleTypeException(final Value val)
|
||||
{
|
||||
this.val = val;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.nbt.StringTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import com.google.gson.JsonElement;
|
||||
@@ -9,6 +10,7 @@ import com.google.gson.JsonNull;
|
||||
public class NullValue extends NumericValue // TODO check nonsingleton code
|
||||
{
|
||||
public static final NullValue NULL = new NullValue();
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
@@ -32,41 +34,45 @@ public class NullValue extends NumericValue // TODO check nonsingleton code
|
||||
{
|
||||
return new NullValue();
|
||||
}
|
||||
protected NullValue() {super(0);}
|
||||
|
||||
protected NullValue()
|
||||
{
|
||||
super(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (o instanceof Value value)
|
||||
{
|
||||
return value.isNull();
|
||||
}
|
||||
return false;
|
||||
return o instanceof Value value && value.isNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value slice(long fromDesc, Long toDesc) {
|
||||
public Value slice(final long fromDesc, final Long toDesc)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumericValue opposite() {
|
||||
public NumericValue opposite()
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
public int length()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Value o)
|
||||
public int compareTo(final Value o)
|
||||
{
|
||||
return o.isNull() ? 0 : -1;
|
||||
return o.isNull() ? 0 : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value in(Value value) {
|
||||
public Value in(final Value value)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
|
||||
@@ -83,15 +89,19 @@ public class NullValue extends NumericValue // TODO check nonsingleton code
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
if (!force)
|
||||
{
|
||||
throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
}
|
||||
return StringTag.valueOf("null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value split(Value delimiter) {
|
||||
return ListValue.wrap(new ArrayList<Value>());
|
||||
public Value split(final Value delimiter)
|
||||
{
|
||||
return ListValue.wrap(new ArrayList<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,7 +111,8 @@ public class NullValue extends NumericValue // TODO check nonsingleton code
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNull() {
|
||||
public boolean isNull()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.minecraft.nbt.DoubleTag;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.nbt.LongTag;
|
||||
@@ -21,28 +22,41 @@ public class NumericValue extends Value
|
||||
{
|
||||
private final double value;
|
||||
private Long longValue;
|
||||
private final static double epsilon = abs(32*((7*0.1)*10-7));
|
||||
private final static MathContext displayRounding = new MathContext(12, RoundingMode.HALF_EVEN);
|
||||
private static final double epsilon = abs(32 * ((7 * 0.1) * 10 - 7));
|
||||
private static final MathContext displayRounding = new MathContext(12, RoundingMode.HALF_EVEN);
|
||||
|
||||
public static NumericValue asNumber(Value v1, String id)
|
||||
public static NumericValue asNumber(final Value v1, final String id)
|
||||
{
|
||||
if (!(v1 instanceof NumericValue))
|
||||
throw new InternalExpressionException("Argument "+id+" has to be of a numeric type");
|
||||
return ((NumericValue) v1);
|
||||
if (v1 instanceof final NumericValue nv)
|
||||
{
|
||||
return nv;
|
||||
}
|
||||
throw new InternalExpressionException("Argument " + id + " has to be of a numeric type");
|
||||
}
|
||||
|
||||
public static NumericValue asNumber(Value v1)
|
||||
public static NumericValue asNumber(final Value v1)
|
||||
{
|
||||
if (!(v1 instanceof NumericValue))
|
||||
throw new InternalExpressionException("Operand has to be of a numeric type");
|
||||
return ((NumericValue) v1);
|
||||
if (v1 instanceof final NumericValue nv)
|
||||
{
|
||||
return nv;
|
||||
}
|
||||
throw new InternalExpressionException("Operand has to be of a numeric type");
|
||||
}
|
||||
|
||||
public static <T extends Number> Value of(T value)
|
||||
public static <T extends Number> Value of(final T value)
|
||||
{
|
||||
if (value == null) return Value.NULL;
|
||||
if (value.doubleValue() == value.longValue()) return new NumericValue(value.longValue());
|
||||
if (value instanceof Float) return new NumericValue(0.000_001D * Math.round(1_000_000.0D*value.doubleValue()));
|
||||
if (value == null)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
if (value.doubleValue() == value.longValue())
|
||||
{
|
||||
return new NumericValue(value.longValue());
|
||||
}
|
||||
if (value instanceof Float)
|
||||
{
|
||||
return new NumericValue(0.000_001D * Math.round(1_000_000.0D * value.doubleValue()));
|
||||
}
|
||||
return new NumericValue(value.doubleValue());
|
||||
}
|
||||
|
||||
@@ -56,30 +70,33 @@ public class NumericValue extends Value
|
||||
}
|
||||
try
|
||||
{
|
||||
if (Double.isInfinite(value)) return (value>0)?"INFINITY":"-INFINITY";
|
||||
if (Double.isNaN(value)) return "NaN";
|
||||
if (abs(value) < epsilon) return (signum(value) < 0)?"-0":"0"; //zero rounding fails with big decimals
|
||||
if (Double.isInfinite(value))
|
||||
{
|
||||
return (value > 0) ? "INFINITY" : "-INFINITY";
|
||||
}
|
||||
if (Double.isNaN(value))
|
||||
{
|
||||
return "NaN";
|
||||
}
|
||||
if (abs(value) < epsilon)
|
||||
{
|
||||
return (signum(value) < 0) ? "-0" : "0"; //zero rounding fails with big decimals
|
||||
}
|
||||
// dobules have 16 point precision, 12 is plenty to display
|
||||
return BigDecimal.valueOf(value).round(displayRounding).stripTrailingZeros().toPlainString();
|
||||
}
|
||||
catch (NumberFormatException exc)
|
||||
catch (final NumberFormatException exc)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect number format for "+value);
|
||||
throw new InternalExpressionException("Incorrect number format for " + value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrettyString()
|
||||
{
|
||||
|
||||
if (longValue!= null || getDouble() == (double)getLong())
|
||||
{
|
||||
return Long.toString(getLong());
|
||||
}
|
||||
else
|
||||
{
|
||||
return String.format(Locale.ROOT, "%.1f..", getDouble());
|
||||
}
|
||||
return longValue != null || getDouble() == getLong()
|
||||
? Long.toString(getLong())
|
||||
: String.format(Locale.ROOT, "%.1f..", getDouble());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,80 +104,62 @@ public class NumericValue extends Value
|
||||
{
|
||||
return abs(value) > epsilon;
|
||||
}
|
||||
|
||||
public double getDouble()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public float getFloat()
|
||||
{
|
||||
return (float) value;
|
||||
}
|
||||
|
||||
private static long floor(double double_1) {
|
||||
long int_1 = (long)double_1;
|
||||
return double_1 < (double)int_1 ? int_1 - 1 : int_1;
|
||||
private static long floor(final double v)
|
||||
{
|
||||
final long invValue = (long) v;
|
||||
return v < invValue ? invValue - 1 : invValue;
|
||||
}
|
||||
|
||||
public long getLong()
|
||||
{
|
||||
if (longValue != null) return longValue;
|
||||
return floor((value+epsilon));
|
||||
return longValue != null ? longValue : Long.valueOf(floor((value + epsilon)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value add(Value v)
|
||||
public Value add(final Value v)
|
||||
{ // TODO test if definintn add(NumericVlaue) woud solve the casting
|
||||
if (v instanceof NumericValue nv)
|
||||
if (v instanceof final NumericValue nv)
|
||||
{
|
||||
if (longValue != null && nv.longValue != null)
|
||||
{
|
||||
return new NumericValue(longValue+nv.longValue);
|
||||
}
|
||||
return new NumericValue(value + nv.value);
|
||||
return new NumericValue(longValue != null && nv.longValue != null ? (longValue + nv.longValue) : (value + nv.value));
|
||||
}
|
||||
return super.add(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value subtract(Value v) { // TODO test if definintn add(NumericVlaue) woud solve the casting
|
||||
if (v instanceof NumericValue nv)
|
||||
public Value subtract(final Value v)
|
||||
{ // TODO test if definintn add(NumericVlaue) woud solve the casting
|
||||
if (v instanceof final NumericValue nv)
|
||||
{
|
||||
if (longValue != null && nv.longValue != null)
|
||||
{
|
||||
return new NumericValue(longValue-nv.longValue);
|
||||
}
|
||||
return new NumericValue(value - nv.value);
|
||||
return new NumericValue(longValue != null && nv.longValue != null ? (longValue - nv.longValue) : (value - nv.value));
|
||||
}
|
||||
return super.subtract(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value multiply(Value v)
|
||||
public Value multiply(final Value v)
|
||||
{
|
||||
if (v instanceof NumericValue nv)
|
||||
if (v instanceof final NumericValue nv)
|
||||
{
|
||||
if (longValue != null && nv.longValue != null)
|
||||
{
|
||||
return new NumericValue(longValue*nv.longValue);
|
||||
}
|
||||
return new NumericValue(value * nv.value);
|
||||
return new NumericValue(longValue != null && nv.longValue != null ? (longValue * nv.longValue) : (value * nv.value));
|
||||
}
|
||||
if (v instanceof ListValue)
|
||||
{
|
||||
return v.multiply(this);
|
||||
}
|
||||
return new StringValue(StringUtils.repeat(v.getString(), (int) getLong()));
|
||||
return v instanceof ListValue ? v.multiply(this) : new StringValue(StringUtils.repeat(v.getString(), (int) getLong()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value divide(Value v)
|
||||
public Value divide(final Value v)
|
||||
{
|
||||
//if (1+2==3) throw new ArithmeticException("Booyah");
|
||||
if (v instanceof NumericValue)
|
||||
{
|
||||
return new NumericValue(getDouble() / ((NumericValue) v).getDouble() );
|
||||
}
|
||||
return super.divide(v);
|
||||
return v instanceof final NumericValue nv ? new NumericValue(getDouble() / nv.getDouble()) : super.divide(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,64 +169,68 @@ public class NumericValue extends Value
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Value o)
|
||||
public int compareTo(final Value o)
|
||||
{
|
||||
if (o.isNull())
|
||||
{
|
||||
return -o.compareTo(this);
|
||||
}
|
||||
if (o instanceof NumericValue no)
|
||||
if (o instanceof final NumericValue no)
|
||||
{
|
||||
if (longValue != null && no.longValue != null)
|
||||
return longValue.compareTo(no.longValue);
|
||||
return Double.compare(value, no.value);
|
||||
return longValue != null && no.longValue != null ? longValue.compareTo(no.longValue) : Double.compare(value, no.value);
|
||||
}
|
||||
return getString().compareTo(o.getString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (o instanceof Value value) {
|
||||
if (value.isNull()) {
|
||||
if (o instanceof final Value otherValue)
|
||||
{
|
||||
if (otherValue.isNull())
|
||||
{
|
||||
return o.equals(this);
|
||||
}
|
||||
if (o instanceof NumericValue no) {
|
||||
if (longValue != null && no.longValue != null)
|
||||
return longValue.equals(no.longValue);
|
||||
return !this.subtract(no).getBoolean();
|
||||
if (o instanceof final NumericValue no)
|
||||
{
|
||||
return longValue != null && no.longValue != null ? longValue.equals(no.longValue) : !this.subtract(no).getBoolean();
|
||||
}
|
||||
return super.equals(o);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public NumericValue(double value)
|
||||
public NumericValue(final double value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
private NumericValue(double value, Long longValue)
|
||||
|
||||
private NumericValue(final double value, final Long longValue)
|
||||
{
|
||||
this.value = value;
|
||||
this.longValue = longValue;
|
||||
}
|
||||
|
||||
public NumericValue(String value)
|
||||
public NumericValue(final String value)
|
||||
{
|
||||
BigDecimal decimal = new BigDecimal(value);
|
||||
final BigDecimal decimal = new BigDecimal(value);
|
||||
if (decimal.stripTrailingZeros().scale() <= 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
longValue = decimal.longValueExact();
|
||||
}
|
||||
catch (ArithmeticException ignored) {}
|
||||
catch (final ArithmeticException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
this.value = decimal.doubleValue();
|
||||
}
|
||||
public NumericValue(long value)
|
||||
|
||||
public NumericValue(final long value)
|
||||
{
|
||||
this.longValue = value;
|
||||
this.value = (double)value;
|
||||
this.value = (double) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -257,31 +260,34 @@ public class NumericValue extends Value
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
if (longValue!= null || Math.abs(Math.floor(value + 0.5D)-value) < epsilon) // is sufficiently close to the integer value
|
||||
return Long.hashCode(getLong());
|
||||
return Double.hashCode(value);
|
||||
// is sufficiently close to the integer value
|
||||
return longValue != null || Math.abs(Math.floor(value + 0.5D) - value) < epsilon ? Long.hashCode(getLong()) : Double.hashCode(value);
|
||||
}
|
||||
|
||||
|
||||
public int getInt()
|
||||
{
|
||||
return (int)getLong();
|
||||
return (int) getLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
if (longValue != null)
|
||||
{
|
||||
if (abs(longValue) < Integer.MAX_VALUE-2)
|
||||
return IntTag.valueOf((int)(long)longValue);
|
||||
if (abs(longValue) < Integer.MAX_VALUE - 2)
|
||||
{
|
||||
return IntTag.valueOf((int) (long) longValue);
|
||||
}
|
||||
return LongTag.valueOf(longValue);
|
||||
}
|
||||
long lv = getLong();
|
||||
if (value == (double)lv)
|
||||
final long lv = getLong();
|
||||
if (value == (double) lv)
|
||||
{
|
||||
if (abs(value) < Integer.MAX_VALUE-2)
|
||||
return IntTag.valueOf((int)lv);
|
||||
if (abs(value) < Integer.MAX_VALUE - 2)
|
||||
{
|
||||
return IntTag.valueOf((int) lv);
|
||||
}
|
||||
return LongTag.valueOf(getLong());
|
||||
}
|
||||
else
|
||||
@@ -294,35 +300,35 @@ public class NumericValue extends Value
|
||||
public JsonElement toJson()
|
||||
{
|
||||
if (longValue != null)
|
||||
{
|
||||
return new JsonPrimitive(longValue);
|
||||
long lv = getLong();
|
||||
if (value == (double)lv)
|
||||
{
|
||||
return new JsonPrimitive(getLong());
|
||||
}
|
||||
else
|
||||
{
|
||||
return new JsonPrimitive(value);
|
||||
}
|
||||
final long lv = getLong();
|
||||
return new JsonPrimitive(value == lv ? getLong() : value);
|
||||
}
|
||||
|
||||
public NumericValue opposite() {
|
||||
if (longValue != null) return new NumericValue(-longValue);
|
||||
return new NumericValue(-value);
|
||||
public NumericValue opposite()
|
||||
{
|
||||
return new NumericValue(longValue != null ? -longValue : -value);
|
||||
}
|
||||
|
||||
public boolean isInteger()
|
||||
{
|
||||
return longValue!= null || getDouble() == (double)getLong();
|
||||
return longValue != null || getDouble() == getLong();
|
||||
}
|
||||
|
||||
public Value mod(NumericValue n2)
|
||||
public Value mod(final NumericValue n2)
|
||||
{
|
||||
if (this.longValue != null && n2.longValue != null)
|
||||
{
|
||||
return new NumericValue(Math.floorMod(longValue, n2.longValue));
|
||||
double x = value;
|
||||
double y = n2.value;
|
||||
if (y == 0) throw new ArithmeticException("Division by zero");
|
||||
return new NumericValue( x - Math.floor(x / y) * y);
|
||||
}
|
||||
final double x = value;
|
||||
final double y = n2.value;
|
||||
if (y == 0)
|
||||
{
|
||||
throw new ArithmeticException("Division by zero");
|
||||
}
|
||||
return new NumericValue(x - Math.floor(x / y) * y);
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,13 @@ import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.exception.InvalidCallbackException;
|
||||
import carpet.script.exception.ThrowStatement;
|
||||
import carpet.script.exception.Throwables;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
@@ -29,37 +31,14 @@ import net.minecraft.world.SimpleContainer;
|
||||
import net.minecraft.world.SimpleMenuProvider;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.AbstractFurnaceMenu;
|
||||
import net.minecraft.world.inventory.AnvilMenu;
|
||||
import net.minecraft.world.inventory.BeaconMenu;
|
||||
import net.minecraft.world.inventory.BlastFurnaceMenu;
|
||||
import net.minecraft.world.inventory.BrewingStandMenu;
|
||||
import net.minecraft.world.inventory.CartographyTableMenu;
|
||||
import net.minecraft.world.inventory.ChestMenu;
|
||||
import net.minecraft.world.inventory.ClickType;
|
||||
import net.minecraft.world.inventory.ContainerListener;
|
||||
import net.minecraft.world.inventory.CraftingMenu;
|
||||
import net.minecraft.world.inventory.DataSlot;
|
||||
import net.minecraft.world.inventory.EnchantmentMenu;
|
||||
import net.minecraft.world.inventory.FurnaceMenu;
|
||||
import net.minecraft.world.inventory.GrindstoneMenu;
|
||||
import net.minecraft.world.inventory.HopperMenu;
|
||||
import net.minecraft.world.inventory.LecternMenu;
|
||||
import net.minecraft.world.inventory.LoomMenu;
|
||||
import net.minecraft.world.inventory.MerchantMenu;
|
||||
import net.minecraft.world.inventory.ShulkerBoxMenu;
|
||||
import net.minecraft.world.inventory.SimpleContainerData;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.inventory.SmithingMenu;
|
||||
import net.minecraft.world.inventory.SmokerMenu;
|
||||
import net.minecraft.world.inventory.StonecutterMenu;
|
||||
import net.minecraft.world.inventory.*;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
|
||||
import static net.minecraft.world.inventory.MenuType.*;
|
||||
|
||||
public class ScreenValue extends Value {
|
||||
public class ScreenValue extends Value
|
||||
{
|
||||
private AbstractContainerMenu screenHandler;
|
||||
private ScreenHandlerInventory inventory;
|
||||
|
||||
@@ -69,83 +48,96 @@ public class ScreenValue extends Value {
|
||||
private final String hostname;
|
||||
private final ServerPlayer player;
|
||||
|
||||
|
||||
public static Map<String,ScarpetScreenHandlerFactory> screenHandlerFactories;
|
||||
public static Map<String, ScarpetScreenHandlerFactory> screenHandlerFactories;
|
||||
|
||||
static
|
||||
{
|
||||
screenHandlerFactories = new HashMap<>();
|
||||
|
||||
screenHandlerFactories.put("anvil",(syncId, playerInventory) -> new AnvilMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("beacon",(syncId, playerInventory) -> new BeaconMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("blast_furnace",(syncId, playerInventory) -> new BlastFurnaceMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("brewing_stand",(syncId, playerInventory) -> new BrewingStandMenu(syncId,playerInventory,new SimpleContainer(5),new SimpleContainerData(2)));
|
||||
screenHandlerFactories.put("cartography_table",(syncId, playerInventory) -> new CartographyTableMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("crafting",(syncId, playerInventory) -> new CraftingMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("enchantment",(syncId, playerInventory) -> new EnchantmentMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("furnace",(syncId, playerInventory) -> new FurnaceMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("generic_3x3",((syncId, playerInventory) -> new ChestMenu(GENERIC_3x3,syncId,playerInventory,new SimpleContainer(9),1)));
|
||||
screenHandlerFactories.put("generic_9x1",((syncId, playerInventory) -> new ChestMenu(GENERIC_9x1,syncId,playerInventory,new SimpleContainer(9),1)));
|
||||
screenHandlerFactories.put("generic_9x2",((syncId, playerInventory) -> new ChestMenu(GENERIC_9x2,syncId,playerInventory,new SimpleContainer(9*2),2)));
|
||||
screenHandlerFactories.put("generic_9x3",((syncId, playerInventory) -> new ChestMenu(GENERIC_9x3,syncId,playerInventory,new SimpleContainer(9*3),3)));
|
||||
screenHandlerFactories.put("generic_9x4",((syncId, playerInventory) -> new ChestMenu(GENERIC_9x4,syncId,playerInventory,new SimpleContainer(9*4),4)));
|
||||
screenHandlerFactories.put("generic_9x5",((syncId, playerInventory) -> new ChestMenu(GENERIC_9x5,syncId,playerInventory,new SimpleContainer(9*5),5)));
|
||||
screenHandlerFactories.put("generic_9x6",((syncId, playerInventory) -> new ChestMenu(GENERIC_9x6,syncId,playerInventory,new SimpleContainer(9*6),6)));
|
||||
screenHandlerFactories.put("grindstone",(syncId, playerInventory) -> new GrindstoneMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("hopper",(syncId, playerInventory) -> new HopperMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("lectern",(syncId, playerInventory) -> new LecternMenu(syncId,new SimpleContainer(1),new SimpleContainerData(1)));
|
||||
screenHandlerFactories.put("loom",(syncId, playerInventory) -> new LoomMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("merchant",(syncId, playerInventory) -> new MerchantMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("shulker_box",(syncId, playerInventory) -> new ShulkerBoxMenu(syncId,playerInventory,new SimpleContainer(9*3)));
|
||||
screenHandlerFactories.put("smithing",(syncId, playerInventory) -> new SmithingMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("smoker",(syncId, playerInventory) -> new SmokerMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("stonecutter",(syncId, playerInventory) -> new StonecutterMenu(syncId,playerInventory));
|
||||
screenHandlerFactories.put("anvil", AnvilMenu::new);
|
||||
screenHandlerFactories.put("beacon", BeaconMenu::new);
|
||||
screenHandlerFactories.put("blast_furnace", BlastFurnaceMenu::new);
|
||||
screenHandlerFactories.put("brewing_stand", (syncId, playerInventory) -> new BrewingStandMenu(syncId, playerInventory, new SimpleContainer(5), new SimpleContainerData(2)));
|
||||
screenHandlerFactories.put("cartography_table", CartographyTableMenu::new);
|
||||
screenHandlerFactories.put("crafting", CraftingMenu::new);
|
||||
screenHandlerFactories.put("enchantment", EnchantmentMenu::new);
|
||||
screenHandlerFactories.put("furnace", FurnaceMenu::new);
|
||||
screenHandlerFactories.put("generic_3x3", ((syncId, playerInventory) -> new ChestMenu(GENERIC_3x3, syncId, playerInventory, new SimpleContainer(9), 1)));
|
||||
screenHandlerFactories.put("generic_9x1", ((syncId, playerInventory) -> new ChestMenu(GENERIC_9x1, syncId, playerInventory, new SimpleContainer(9), 1)));
|
||||
screenHandlerFactories.put("generic_9x2", ((syncId, playerInventory) -> new ChestMenu(GENERIC_9x2, syncId, playerInventory, new SimpleContainer(9 * 2), 2)));
|
||||
screenHandlerFactories.put("generic_9x3", ((syncId, playerInventory) -> new ChestMenu(GENERIC_9x3, syncId, playerInventory, new SimpleContainer(9 * 3), 3)));
|
||||
screenHandlerFactories.put("generic_9x4", ((syncId, playerInventory) -> new ChestMenu(GENERIC_9x4, syncId, playerInventory, new SimpleContainer(9 * 4), 4)));
|
||||
screenHandlerFactories.put("generic_9x5", ((syncId, playerInventory) -> new ChestMenu(GENERIC_9x5, syncId, playerInventory, new SimpleContainer(9 * 5), 5)));
|
||||
screenHandlerFactories.put("generic_9x6", ((syncId, playerInventory) -> new ChestMenu(GENERIC_9x6, syncId, playerInventory, new SimpleContainer(9 * 6), 6)));
|
||||
screenHandlerFactories.put("grindstone", GrindstoneMenu::new);
|
||||
screenHandlerFactories.put("hopper", HopperMenu::new);
|
||||
screenHandlerFactories.put("lectern", (syncId, playerInventory) -> new LecternMenu(syncId, new SimpleContainer(1), new SimpleContainerData(1)));
|
||||
screenHandlerFactories.put("loom", LoomMenu::new);
|
||||
screenHandlerFactories.put("merchant", MerchantMenu::new);
|
||||
screenHandlerFactories.put("shulker_box", (syncId, playerInventory) -> new ShulkerBoxMenu(syncId, playerInventory, new SimpleContainer(9 * 3)));
|
||||
screenHandlerFactories.put("smithing_legacy", LegacySmithingMenu::new);
|
||||
screenHandlerFactories.put("smithing", SmithingMenu::new);
|
||||
screenHandlerFactories.put("smoker", SmokerMenu::new);
|
||||
screenHandlerFactories.put("stonecutter", StonecutterMenu::new);
|
||||
}
|
||||
|
||||
|
||||
protected interface ScarpetScreenHandlerFactory {
|
||||
protected interface ScarpetScreenHandlerFactory
|
||||
{
|
||||
AbstractContainerMenu create(int syncId, Inventory playerInventory);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public ScreenValue(ServerPlayer player, String type, Component name, FunctionValue callback, Context c) {
|
||||
public ScreenValue(final ServerPlayer player, final String type, final Component name, final FunctionValue callback, final Context c)
|
||||
{
|
||||
this.name = name;
|
||||
this.typestring = type.toLowerCase();
|
||||
if(callback != null) callback.checkArgs(4);
|
||||
if (callback != null)
|
||||
{
|
||||
callback.checkArgs(4);
|
||||
}
|
||||
this.callback = callback;
|
||||
this.hostname = c.host.getName();
|
||||
this.player = player;
|
||||
MenuProvider factory = this.createScreenHandlerFactory();
|
||||
if(factory == null) throw new ThrowStatement(type, Throwables.UNKNOWN_SCREEN);
|
||||
final MenuProvider factory = this.createScreenHandlerFactory();
|
||||
if (factory == null)
|
||||
{
|
||||
throw new ThrowStatement(type, Throwables.UNKNOWN_SCREEN);
|
||||
}
|
||||
this.openScreen(factory);
|
||||
this.inventory = new ScreenHandlerInventory(this.screenHandler);
|
||||
}
|
||||
|
||||
private MenuProvider createScreenHandlerFactory() {
|
||||
if(!screenHandlerFactories.containsKey(this.typestring)) {
|
||||
private MenuProvider createScreenHandlerFactory()
|
||||
{
|
||||
if (!screenHandlerFactories.containsKey(this.typestring))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SimpleMenuProvider((i, playerInventory, playerEntity) -> {
|
||||
AbstractContainerMenu screen = screenHandlerFactories.get(ScreenValue.this.typestring).create(i,playerInventory);
|
||||
final AbstractContainerMenu screen = screenHandlerFactories.get(ScreenValue.this.typestring).create(i, playerInventory);
|
||||
ScreenValue.this.addListenerCallback(screen);
|
||||
ScreenValue.this.screenHandler = screen;
|
||||
return screen;
|
||||
}, this.name);
|
||||
}
|
||||
|
||||
private void openScreen(MenuProvider factory) {
|
||||
if(this.player == null) return;
|
||||
OptionalInt optionalSyncId = this.player.openMenu(factory);
|
||||
if(optionalSyncId.isPresent() && this.player.containerMenu.containerId == optionalSyncId.getAsInt()) {
|
||||
private void openScreen(final MenuProvider factory)
|
||||
{
|
||||
if (this.player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
final OptionalInt optionalSyncId = this.player.openMenu(factory);
|
||||
if (optionalSyncId.isPresent() && this.player.containerMenu.containerId == optionalSyncId.getAsInt())
|
||||
{
|
||||
this.screenHandler = this.player.containerMenu;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if(this.player.containerMenu != this.player.inventoryMenu) {
|
||||
public void close()
|
||||
{
|
||||
if (this.player.containerMenu != this.player.inventoryMenu)
|
||||
{
|
||||
//prevent recursion when closing screen in closing screen callback by doing this before triggering event
|
||||
this.inventory = null;
|
||||
this.player.containerMenu = this.player.inventoryMenu;
|
||||
@@ -154,11 +146,14 @@ public class ScreenValue extends Value {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
if(this.screenHandler == null) {
|
||||
public boolean isOpen()
|
||||
{
|
||||
if (this.screenHandler == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(this.player.containerMenu.containerId == this.screenHandler.containerId) {
|
||||
if (this.player.containerMenu.containerId == this.screenHandler.containerId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
this.screenHandler = null;
|
||||
@@ -166,104 +161,124 @@ public class ScreenValue extends Value {
|
||||
}
|
||||
|
||||
|
||||
private boolean callListener(ServerPlayer player, String action, Map<Value,Value> data) {
|
||||
Value playerValue = EntityValue.of(player);
|
||||
Value actionValue = StringValue.of(action);
|
||||
Value dataValue = MapValue.wrap(data);
|
||||
List<Value> args = Arrays.asList(this,playerValue,actionValue,dataValue);
|
||||
CarpetScriptHost appHost = CarpetServer.scriptServer.getAppHostByName(this.hostname);
|
||||
if(appHost == null) {
|
||||
private boolean callListener(final ServerPlayer player, final String action, final Map<Value, Value> data)
|
||||
{
|
||||
final Value playerValue = EntityValue.of(player);
|
||||
final Value actionValue = StringValue.of(action);
|
||||
final Value dataValue = MapValue.wrap(data);
|
||||
final List<Value> args = Arrays.asList(this, playerValue, actionValue, dataValue);
|
||||
final CarpetScriptHost appHost = CarpetServer.scriptServer.getAppHostByName(this.hostname);
|
||||
if (appHost == null)
|
||||
{
|
||||
this.close();
|
||||
this.screenHandler = null;
|
||||
return false;
|
||||
}
|
||||
CommandSourceStack source = player.createCommandSourceStack().withPermission(CarpetSettings.runPermissionLevel);
|
||||
CarpetScriptHost executingHost = appHost.retrieveForExecution(source,player);
|
||||
final CommandSourceStack source = player.createCommandSourceStack().withPermission(CarpetSettings.runPermissionLevel);
|
||||
final CarpetScriptHost executingHost = appHost.retrieveForExecution(source, player);
|
||||
try
|
||||
{
|
||||
Value cancelValue = executingHost.callUDF(source.withPermission(CarpetSettings.runPermissionLevel), callback, args);
|
||||
final Value cancelValue = executingHost.callUDF(source.withPermission(CarpetSettings.runPermissionLevel), callback, args);
|
||||
return cancelValue.getString().equals("cancel");
|
||||
}
|
||||
catch (NullPointerException | InvalidCallbackException | IntegrityException error)
|
||||
catch (final NullPointerException | InvalidCallbackException | IntegrityException error)
|
||||
{
|
||||
CarpetScriptServer.LOG.error("Got exception when running screen event call ", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void addListenerCallback(AbstractContainerMenu screenHandler) {
|
||||
if(this.callback == null) return;
|
||||
private void addListenerCallback(final AbstractContainerMenu screenHandler)
|
||||
{
|
||||
if (this.callback == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
screenHandler.addSlotListener(new ScarpetScreenHandlerListener() {
|
||||
screenHandler.addSlotListener(new ScarpetScreenHandlerListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onSlotClick(ServerPlayer player, ClickType actionType, int slot, int button) {
|
||||
Map<Value,Value> data = new HashMap<>();
|
||||
data.put(StringValue.of("slot"),slot == AbstractContainerMenu.SLOT_CLICKED_OUTSIDE ? Value.NULL : NumericValue.of(slot));
|
||||
if(actionType == ClickType.QUICK_CRAFT) {
|
||||
data.put(StringValue.of("quick_craft_stage"),NumericValue.of(AbstractContainerMenu.getQuickcraftHeader(button)));
|
||||
public boolean onSlotClick(final ServerPlayer player, final ClickType actionType, final int slot, int button)
|
||||
{
|
||||
final Map<Value, Value> data = new HashMap<>();
|
||||
data.put(StringValue.of("slot"), slot == AbstractContainerMenu.SLOT_CLICKED_OUTSIDE ? Value.NULL : NumericValue.of(slot));
|
||||
if (actionType == ClickType.QUICK_CRAFT)
|
||||
{
|
||||
data.put(StringValue.of("quick_craft_stage"), NumericValue.of(AbstractContainerMenu.getQuickcraftHeader(button)));
|
||||
button = AbstractContainerMenu.getQuickcraftType(button);
|
||||
}
|
||||
data.put(StringValue.of("button"),NumericValue.of(button));
|
||||
return ScreenValue.this.callListener(player,actionTypeToString(actionType),data);
|
||||
data.put(StringValue.of("button"), NumericValue.of(button));
|
||||
return ScreenValue.this.callListener(player, actionTypeToString(actionType), data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onButtonClick(ServerPlayer player, int button) {
|
||||
Map<Value,Value> data = new HashMap<>();
|
||||
data.put(StringValue.of("button"),NumericValue.of(button));
|
||||
return ScreenValue.this.callListener(player,"button",data);
|
||||
public boolean onButtonClick(final ServerPlayer player, final int button)
|
||||
{
|
||||
final Map<Value, Value> data = new HashMap<>();
|
||||
data.put(StringValue.of("button"), NumericValue.of(button));
|
||||
return ScreenValue.this.callListener(player, "button", data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(ServerPlayer player) {
|
||||
Map<Value,Value> data = new HashMap<>();
|
||||
ScreenValue.this.callListener(player,"close",data);
|
||||
public void onClose(final ServerPlayer player)
|
||||
{
|
||||
final Map<Value, Value> data = new HashMap<>();
|
||||
ScreenValue.this.callListener(player, "close", data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSelectRecipe(ServerPlayer player, Recipe<?> recipe, boolean craftAll) {
|
||||
Map<Value,Value> data = new HashMap<>();
|
||||
data.put(StringValue.of("recipe"),StringValue.of(recipe.getId().toString()));
|
||||
data.put(StringValue.of("craft_all"),BooleanValue.of(craftAll));
|
||||
return ScreenValue.this.callListener(player,"select_recipe",data);
|
||||
public boolean onSelectRecipe(final ServerPlayer player, final Recipe<?> recipe, final boolean craftAll)
|
||||
{
|
||||
final Map<Value, Value> data = new HashMap<>();
|
||||
data.put(StringValue.of("recipe"), StringValue.of(recipe.getId().toString()));
|
||||
data.put(StringValue.of("craft_all"), BooleanValue.of(craftAll));
|
||||
return ScreenValue.this.callListener(player, "select_recipe", data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void slotChanged(AbstractContainerMenu handler, int slotId, ItemStack stack) {
|
||||
Map<Value,Value> data = new HashMap<>();
|
||||
data.put(StringValue.of("slot"),NumericValue.of(slotId));
|
||||
data.put(StringValue.of("stack"),ValueConversions.of(stack, player.level.registryAccess()));
|
||||
ScreenValue.this.callListener(ScreenValue.this.player,"slot_update",data);
|
||||
public void slotChanged(final AbstractContainerMenu handler, final int slotId, final ItemStack stack)
|
||||
{
|
||||
final Map<Value, Value> data = new HashMap<>();
|
||||
data.put(StringValue.of("slot"), NumericValue.of(slotId));
|
||||
data.put(StringValue.of("stack"), ValueConversions.of(stack, player.level.registryAccess()));
|
||||
ScreenValue.this.callListener(ScreenValue.this.player, "slot_update", data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataChanged(AbstractContainerMenu handler, int property, int value) {}
|
||||
public void dataChanged(final AbstractContainerMenu handler, final int property, final int value)
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private DataSlot getPropertyForType(Class<? extends AbstractContainerMenu> screenHandlerClass, String requiredType, int propertyIndex, String propertyName) {
|
||||
if(screenHandlerClass.isInstance(this.screenHandler)) {
|
||||
private DataSlot getPropertyForType(final Class<? extends AbstractContainerMenu> screenHandlerClass, final String requiredType, final int propertyIndex, final String propertyName)
|
||||
{
|
||||
if (screenHandlerClass.isInstance(this.screenHandler))
|
||||
{
|
||||
return ((ScreenHandlerInterface) this.screenHandler).getProperty(propertyIndex);
|
||||
}
|
||||
if(!this.isOpen()) {
|
||||
if (!this.isOpen())
|
||||
{
|
||||
throw new InternalExpressionException("Screen property cannot be accessed, because the screen is already closed");
|
||||
}
|
||||
throw new InternalExpressionException("Screen property " + propertyName + " expected a " + requiredType + " screen.");
|
||||
}
|
||||
|
||||
private DataSlot getProperty(String propertyName) {
|
||||
return switch (propertyName) {
|
||||
private DataSlot getProperty(final String propertyName)
|
||||
{
|
||||
return switch (propertyName)
|
||||
{
|
||||
case "fuel_progress" -> getPropertyForType(AbstractFurnaceMenu.class, "furnace", 0, propertyName);
|
||||
case "max_fuel_progress" -> getPropertyForType(AbstractFurnaceMenu.class, "furnace", 1, propertyName);
|
||||
case "cook_progress" -> getPropertyForType(AbstractFurnaceMenu.class, "furnace", 2, propertyName);
|
||||
case "max_cook_progress" -> getPropertyForType(AbstractFurnaceMenu.class, "furnace", 3, propertyName);
|
||||
|
||||
case "level_cost" -> getPropertyForType(AnvilMenu.class, "anvil", 0, propertyName);
|
||||
|
||||
case "page" -> getPropertyForType(LecternMenu.class, "lectern", 0, propertyName);
|
||||
|
||||
case "beacon_level" -> getPropertyForType(BeaconMenu.class, "beacon", 0, propertyName);
|
||||
case "primary_effect" -> getPropertyForType(BeaconMenu.class, "beacon", 1, propertyName);
|
||||
case "secondary_effect" -> getPropertyForType(BeaconMenu.class, "beacon", 2, propertyName);
|
||||
|
||||
case "brew_time" -> getPropertyForType(BrewingStandMenu.class, "brewing_stand", 0, propertyName);
|
||||
case "brewing_fuel" -> getPropertyForType(BrewingStandMenu.class, "brewing_stand", 1, propertyName);
|
||||
|
||||
case "enchantment_power_1" -> getPropertyForType(EnchantmentMenu.class, "enchantment", 0, propertyName);
|
||||
case "enchantment_power_2" -> getPropertyForType(EnchantmentMenu.class, "enchantment", 1, propertyName);
|
||||
case "enchantment_power_3" -> getPropertyForType(EnchantmentMenu.class, "enchantment", 2, propertyName);
|
||||
@@ -274,50 +289,55 @@ public class ScreenValue extends Value {
|
||||
case "enchantment_level_1" -> getPropertyForType(EnchantmentMenu.class, "enchantment", 7, propertyName);
|
||||
case "enchantment_level_2" -> getPropertyForType(EnchantmentMenu.class, "enchantment", 8, propertyName);
|
||||
case "enchantment_level_3" -> getPropertyForType(EnchantmentMenu.class, "enchantment", 9, propertyName);
|
||||
|
||||
case "banner_pattern" -> getPropertyForType(LoomMenu.class, "loom", 0, propertyName);
|
||||
|
||||
case "stonecutter_recipe" -> getPropertyForType(StonecutterMenu.class, "stonecutter", 0, propertyName);
|
||||
|
||||
default -> throw new InternalExpressionException("Invalid screen property: " + propertyName);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public Value queryProperty(String propertyName) {
|
||||
if(propertyName.equals("name")) return FormattedTextValue.of(this.name);
|
||||
if(propertyName.equals("open")) return BooleanValue.of(this.isOpen());
|
||||
DataSlot property = getProperty(propertyName);
|
||||
public Value queryProperty(final String propertyName)
|
||||
{
|
||||
if (propertyName.equals("name"))
|
||||
{
|
||||
return FormattedTextValue.of(this.name);
|
||||
}
|
||||
if (propertyName.equals("open"))
|
||||
{
|
||||
return BooleanValue.of(this.isOpen());
|
||||
}
|
||||
final DataSlot property = getProperty(propertyName);
|
||||
return NumericValue.of(property.get());
|
||||
}
|
||||
|
||||
public Value modifyProperty(String propertyName, List<Value> lv) {
|
||||
DataSlot property = getProperty(propertyName);
|
||||
int intValue = NumericValue.asNumber(lv.get(0)).getInt();
|
||||
public Value modifyProperty(final String propertyName, final List<Value> lv)
|
||||
{
|
||||
final DataSlot property = getProperty(propertyName);
|
||||
final int intValue = NumericValue.asNumber(lv.get(0)).getInt();
|
||||
property.set(intValue);
|
||||
this.screenHandler.sendAllDataToRemote();
|
||||
return Value.TRUE;
|
||||
}
|
||||
|
||||
public AbstractContainerMenu getScreenHandler() {
|
||||
return this.screenHandler;
|
||||
}
|
||||
|
||||
public ServerPlayer getPlayer() {
|
||||
public ServerPlayer getPlayer()
|
||||
{
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public Container getInventory() {
|
||||
public Container getInventory()
|
||||
{
|
||||
return this.inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
public String getString()
|
||||
{
|
||||
return this.typestring + "_screen";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean() {
|
||||
public boolean getBoolean()
|
||||
{
|
||||
return this.isOpen();
|
||||
}
|
||||
|
||||
@@ -328,92 +348,134 @@ public class ScreenValue extends Value {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force) {
|
||||
if(this.screenHandler == null) {
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
if (this.screenHandler == null)
|
||||
{
|
||||
return Value.NULL.toTag(true);
|
||||
}
|
||||
|
||||
ListTag nbtList = new ListTag();
|
||||
for(int i = 0; i < this.screenHandler.slots.size(); i++) {
|
||||
ItemStack itemStack = this.screenHandler.getSlot(i).getItem();
|
||||
final ListTag nbtList = new ListTag();
|
||||
for (int i = 0; i < this.screenHandler.slots.size(); i++)
|
||||
{
|
||||
final ItemStack itemStack = this.screenHandler.getSlot(i).getItem();
|
||||
nbtList.add(itemStack.save(new CompoundTag()));
|
||||
}
|
||||
return nbtList;
|
||||
}
|
||||
|
||||
|
||||
public interface ScarpetScreenHandlerListener extends ContainerListener {
|
||||
public interface ScarpetScreenHandlerListener extends ContainerListener
|
||||
{
|
||||
boolean onSlotClick(ServerPlayer player, ClickType actionType, int slot, int button);
|
||||
|
||||
boolean onButtonClick(ServerPlayer player, int button);
|
||||
|
||||
void onClose(ServerPlayer player);
|
||||
|
||||
boolean onSelectRecipe(ServerPlayer player, Recipe<?> recipe, boolean craftAll);
|
||||
}
|
||||
|
||||
public static class ScreenHandlerInventory implements Container {
|
||||
|
||||
public static class ScreenHandlerInventory implements Container
|
||||
{
|
||||
protected AbstractContainerMenu screenHandler;
|
||||
|
||||
public ScreenHandlerInventory(AbstractContainerMenu screenHandler) {
|
||||
public ScreenHandlerInventory(final AbstractContainerMenu screenHandler)
|
||||
{
|
||||
this.screenHandler = screenHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContainerSize() {
|
||||
public int getContainerSize()
|
||||
{
|
||||
return this.screenHandler.slots.size() + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for(Slot slot : this.screenHandler.slots) {
|
||||
if(slot.hasItem() && !slot.getItem().isEmpty()) return false;
|
||||
public boolean isEmpty()
|
||||
{
|
||||
for (final Slot slot : this.screenHandler.slots)
|
||||
{
|
||||
if (slot.hasItem() && !slot.getItem().isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return this.screenHandler.getCarried().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int slot) {
|
||||
if(slot == this.getContainerSize()-1) return this.screenHandler.getCarried();
|
||||
public ItemStack getItem(final int slot)
|
||||
{
|
||||
if (slot == this.getContainerSize() - 1)
|
||||
{
|
||||
return this.screenHandler.getCarried();
|
||||
}
|
||||
return slot >= -1 && slot < this.getContainerSize() ? this.screenHandler.slots.get(slot).getItem() : ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItem(int slot, int amount) {
|
||||
ItemStack itemStack;
|
||||
if(slot == this.getContainerSize()-1)
|
||||
public ItemStack removeItem(final int slot, final int amount)
|
||||
{
|
||||
final ItemStack itemStack;
|
||||
if (slot == this.getContainerSize() - 1)
|
||||
{
|
||||
itemStack = this.screenHandler.getCarried().split(amount);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemStack = ScreenHandlerInventory.splitStack(this.screenHandler.slots, slot, amount);
|
||||
if (!itemStack.isEmpty()) {
|
||||
}
|
||||
if (!itemStack.isEmpty())
|
||||
{
|
||||
this.setChanged();
|
||||
}
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItemNoUpdate(int slot) {
|
||||
ItemStack itemStack;
|
||||
if(slot == this.getContainerSize()-1)
|
||||
public ItemStack removeItemNoUpdate(final int slot)
|
||||
{
|
||||
final ItemStack itemStack;
|
||||
if (slot == this.getContainerSize() - 1)
|
||||
{
|
||||
itemStack = this.screenHandler.getCarried();
|
||||
}
|
||||
else
|
||||
{
|
||||
itemStack = this.screenHandler.slots.get(slot).getItem();
|
||||
if (itemStack.isEmpty()) {
|
||||
}
|
||||
if (itemStack.isEmpty())
|
||||
{
|
||||
return ItemStack.EMPTY;
|
||||
} else {
|
||||
if(slot == this.getContainerSize()-1)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (slot == this.getContainerSize() - 1)
|
||||
{
|
||||
this.screenHandler.setCarried(ItemStack.EMPTY);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.screenHandler.slots.get(slot).set(ItemStack.EMPTY);
|
||||
}
|
||||
return itemStack;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(int slot, ItemStack stack) {
|
||||
if(slot == this.getContainerSize()-1)
|
||||
public void setItem(final int slot, final ItemStack stack)
|
||||
{
|
||||
if (slot == this.getContainerSize() - 1)
|
||||
{
|
||||
this.screenHandler.setCarried(stack);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.screenHandler.slots.get(slot).set(stack);
|
||||
if (!stack.isEmpty() && stack.getCount() > this.getMaxStackSize()) {
|
||||
}
|
||||
if (!stack.isEmpty() && stack.getCount() > this.getMaxStackSize())
|
||||
{
|
||||
stack.setCount(this.getMaxStackSize());
|
||||
}
|
||||
|
||||
@@ -421,18 +483,21 @@ public class ScreenValue extends Value {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChanged() {
|
||||
|
||||
public void setChanged()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stillValid(Player player) {
|
||||
public boolean stillValid(final Player player)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearContent() {
|
||||
for(Slot slot : this.screenHandler.slots) {
|
||||
public void clearContent()
|
||||
{
|
||||
for (final Slot slot : this.screenHandler.slots)
|
||||
{
|
||||
slot.set(ItemStack.EMPTY);
|
||||
}
|
||||
this.screenHandler.setCarried(ItemStack.EMPTY);
|
||||
@@ -440,13 +505,16 @@ public class ScreenValue extends Value {
|
||||
}
|
||||
|
||||
|
||||
public static ItemStack splitStack(List<Slot> slots, int slot, int amount) {
|
||||
public static ItemStack splitStack(final List<Slot> slots, final int slot, final int amount)
|
||||
{
|
||||
return slot >= 0 && slot < slots.size() && !slots.get(slot).getItem().isEmpty() && amount > 0 ? slots.get(slot).getItem().split(amount) : ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
private static String actionTypeToString(ClickType actionType) {
|
||||
return switch (actionType) {
|
||||
private static String actionTypeToString(final ClickType actionType)
|
||||
{
|
||||
return switch (actionType)
|
||||
{
|
||||
case PICKUP -> "pickup";
|
||||
case QUICK_MOVE -> "quick_move";
|
||||
case SWAP -> "swap";
|
||||
|
||||
@@ -7,15 +7,17 @@ public class StringValue extends Value
|
||||
{
|
||||
public static Value EMPTY = StringValue.of("");
|
||||
|
||||
private String str;
|
||||
private final String str;
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
public String getString()
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean() {
|
||||
public boolean getBoolean()
|
||||
{
|
||||
return str != null && !str.isEmpty();
|
||||
}
|
||||
|
||||
@@ -25,15 +27,14 @@ public class StringValue extends Value
|
||||
return new StringValue(str);
|
||||
}
|
||||
|
||||
public StringValue(String str)
|
||||
public StringValue(final String str)
|
||||
{
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
public static Value of(String value)
|
||||
public static Value of(final String value)
|
||||
{
|
||||
if (value == null) return Value.NULL;
|
||||
return new StringValue(value);
|
||||
return value == null ? Value.NULL : new StringValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -43,7 +44,7 @@ public class StringValue extends Value
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
return StringTag.valueOf(str);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ import carpet.script.Tokenizer;
|
||||
import carpet.script.exception.ExitStatement;
|
||||
import carpet.script.exception.ExpressionException;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import net.minecraft.nbt.Tag;
|
||||
|
||||
public class ThreadValue extends Value
|
||||
@@ -18,21 +20,21 @@ public class ThreadValue extends Value
|
||||
private final long id;
|
||||
private static long sequence = 0L;
|
||||
|
||||
public ThreadValue(CompletableFuture<Value> taskFuture)
|
||||
public ThreadValue(final CompletableFuture<Value> taskFuture)
|
||||
{
|
||||
this.taskFuture = taskFuture;
|
||||
this.id = sequence++;
|
||||
}
|
||||
|
||||
public ThreadValue(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<Value> args)
|
||||
public ThreadValue(final Value pool, final FunctionValue function, final Expression expr, final Tokenizer.Token token, final Context ctx, final List<Value> args)
|
||||
{
|
||||
this(getCompletableFutureFromFunction(pool, function, expr, token, ctx, args));
|
||||
Thread.yield();
|
||||
}
|
||||
|
||||
public static CompletableFuture<Value> getCompletableFutureFromFunction(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<Value> args)
|
||||
public static CompletableFuture<Value> getCompletableFutureFromFunction(final Value pool, final FunctionValue function, final Expression expr, final Tokenizer.Token token, final Context ctx, final List<Value> args)
|
||||
{
|
||||
ExecutorService executor = ctx.host.getExecutor(pool);
|
||||
final ExecutorService executor = ctx.host.getExecutor(pool);
|
||||
if (executor == null)
|
||||
{
|
||||
// app is shutting down - no more threads can be spawned.
|
||||
@@ -40,27 +42,22 @@ public class ThreadValue extends Value
|
||||
}
|
||||
else
|
||||
{
|
||||
return CompletableFuture.supplyAsync(
|
||||
() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
return function.execute(ctx, Context.NONE, expr, token, args).evalValue(ctx);
|
||||
}
|
||||
catch (ExitStatement exit)
|
||||
{
|
||||
// app stopped
|
||||
return exit.retval;
|
||||
}
|
||||
catch (ExpressionException exc)
|
||||
{
|
||||
ctx.host.handleExpressionException("Thread failed\n", exc);
|
||||
return Value.NULL;
|
||||
}
|
||||
|
||||
},
|
||||
ctx.host.getExecutor(pool)
|
||||
);
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try
|
||||
{
|
||||
return function.execute(ctx, Context.NONE, expr, token, args).evalValue(ctx);
|
||||
}
|
||||
catch (final ExitStatement exit)
|
||||
{
|
||||
// app stopped
|
||||
return exit.retval;
|
||||
}
|
||||
catch (final ExpressionException exc)
|
||||
{
|
||||
ctx.host.handleExpressionException("Thread failed\n", exc);
|
||||
return Value.NULL;
|
||||
}
|
||||
}, ctx.host.getExecutor(pool));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,12 +84,12 @@ public class ThreadValue extends Value
|
||||
{
|
||||
return taskFuture.get();
|
||||
}
|
||||
catch (ExitStatement exit)
|
||||
catch (final ExitStatement exit)
|
||||
{
|
||||
taskFuture.complete(exit.retval);
|
||||
return exit.retval;
|
||||
}
|
||||
catch (InterruptedException | ExecutionException e)
|
||||
catch (final InterruptedException | ExecutionException e)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
@@ -104,19 +101,19 @@ public class ThreadValue extends Value
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (!(o instanceof ThreadValue))
|
||||
return false;
|
||||
return ((ThreadValue) o).id == this.id;
|
||||
return o instanceof final ThreadValue tv && tv.id == this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Value o)
|
||||
public int compareTo(final Value o)
|
||||
{
|
||||
if (!(o instanceof ThreadValue))
|
||||
if (!(o instanceof final ThreadValue tv))
|
||||
{
|
||||
throw new InternalExpressionException("Cannot compare tasks to other types");
|
||||
return (int) (this.id - ((ThreadValue) o).id);
|
||||
}
|
||||
return (int) (this.id - tv.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,9 +123,12 @@ public class ThreadValue extends Value
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
if (!force)
|
||||
{
|
||||
throw new NBTSerializableValue.IncompatibleTypeException(this);
|
||||
}
|
||||
return getValue().toTag(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,15 @@ import carpet.script.exception.InternalExpressionException;
|
||||
import com.google.gson.JsonElement;
|
||||
import net.minecraft.nbt.Tag;
|
||||
|
||||
public class UndefValue extends NullValue {
|
||||
public class UndefValue extends NullValue
|
||||
{
|
||||
public static final UndefValue UNDEF = new UndefValue();
|
||||
|
||||
private RuntimeException getError() {
|
||||
return new InternalExpressionException("variable "+boundVariable+" was used before initialization under 'strict' app config");
|
||||
private RuntimeException getError()
|
||||
{
|
||||
return new InternalExpressionException("variable " + boundVariable + " was used before initialization under 'strict' app config");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
@@ -43,28 +44,32 @@ public class UndefValue extends NullValue {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value slice(long fromDesc, Long toDesc) {
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumericValue opposite() {
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Value o)
|
||||
public Value slice(final long fromDesc, final Long toDesc)
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value in(Value value) {
|
||||
public NumericValue opposite()
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length()
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final Value o)
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value in(final Value value)
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@@ -81,13 +86,14 @@ public class UndefValue extends NullValue {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toTag(boolean force)
|
||||
public Tag toTag(final boolean force)
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value split(Value delimiter) {
|
||||
public Value split(final Value delimiter)
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@@ -98,29 +104,31 @@ public class UndefValue extends NullValue {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNull() {
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value add(Value v) {
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value subtract(Value v)
|
||||
public boolean isNull()
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value multiply(Value v)
|
||||
public Value add(final Value v)
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value divide(Value v)
|
||||
public Value subtract(final Value v)
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value multiply(final Value v)
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value divide(final Value v)
|
||||
{
|
||||
throw getError();
|
||||
}
|
||||
|
||||
@@ -4,23 +4,25 @@ import carpet.CarpetSettings;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import net.minecraft.nbt.Tag;
|
||||
|
||||
public abstract class Value implements Comparable<Value>, Cloneable
|
||||
{
|
||||
public static NumericValue FALSE = BooleanValue.FALSE;
|
||||
public static NumericValue TRUE = BooleanValue.TRUE;
|
||||
public static NumericValue ZERO = new NumericValue(0);
|
||||
public static NumericValue ONE = new NumericValue(1);
|
||||
public static final NumericValue FALSE = BooleanValue.FALSE;
|
||||
public static final NumericValue TRUE = BooleanValue.TRUE;
|
||||
public static final NumericValue ZERO = new NumericValue(0);
|
||||
public static final NumericValue ONE = new NumericValue(1);
|
||||
|
||||
public static NullValue NULL = NullValue.NULL;
|
||||
public static UndefValue UNDEF = UndefValue.UNDEF;
|
||||
public static final NullValue NULL = NullValue.NULL;
|
||||
public static final UndefValue UNDEF = UndefValue.UNDEF;
|
||||
|
||||
public String boundVariable;
|
||||
|
||||
@@ -28,29 +30,32 @@ public abstract class Value implements Comparable<Value>, Cloneable
|
||||
{
|
||||
return boundVariable != null;
|
||||
}
|
||||
|
||||
public String getVariable()
|
||||
{
|
||||
return boundVariable;
|
||||
}
|
||||
public Value reboundedTo(String var)
|
||||
|
||||
public Value reboundedTo(final String value)
|
||||
{
|
||||
Value copy;
|
||||
final Value copy;
|
||||
try
|
||||
{
|
||||
copy = (Value)clone();
|
||||
copy = (Value) clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
catch (final CloneNotSupportedException e)
|
||||
{
|
||||
// should not happen
|
||||
CarpetSettings.LOG.error("Failed to clone variable", e);
|
||||
throw new InternalExpressionException("Variable of type "+getTypeString()+" is not cloneable. Tell gnembon about it, this shoudn't happen");
|
||||
throw new InternalExpressionException("Variable of type " + getTypeString() + " is not cloneable. Tell gnembon about it, this shoudn't happen");
|
||||
}
|
||||
copy.boundVariable = var;
|
||||
copy.boundVariable = value;
|
||||
return copy;
|
||||
}
|
||||
public Value bindTo(String var)
|
||||
|
||||
public Value bindTo(final String value)
|
||||
{
|
||||
this.boundVariable = var;
|
||||
this.boundVariable = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -64,35 +69,37 @@ public abstract class Value implements Comparable<Value>, Cloneable
|
||||
|
||||
public abstract boolean getBoolean();
|
||||
|
||||
public Value add(Value o) {
|
||||
public Value add(final Value o)
|
||||
{
|
||||
if (o instanceof FormattedTextValue)
|
||||
{
|
||||
return FormattedTextValue.combine(this, o);
|
||||
}
|
||||
String leftStr = this.getString();
|
||||
String rightStr = o.getString();
|
||||
final String leftStr = this.getString();
|
||||
final String rightStr = o.getString();
|
||||
return new StringValue(leftStr + rightStr);
|
||||
}
|
||||
public Value subtract(Value v)
|
||||
|
||||
public Value subtract(final Value v)
|
||||
{
|
||||
return new StringValue(this.getString().replace(v.getString(),""));
|
||||
return new StringValue(this.getString().replace(v.getString(), ""));
|
||||
}
|
||||
public Value multiply(Value v)
|
||||
|
||||
public Value multiply(final Value v)
|
||||
{
|
||||
if (v instanceof NumericValue || v instanceof ListValue)
|
||||
{
|
||||
return v.multiply(this);
|
||||
}
|
||||
return new StringValue(this.getString()+"."+v.getString());
|
||||
return v instanceof NumericValue || v instanceof ListValue
|
||||
? v.multiply(this)
|
||||
: new StringValue(this.getString() + "." + v.getString());
|
||||
}
|
||||
public Value divide(Value v)
|
||||
|
||||
public Value divide(final Value v)
|
||||
{
|
||||
if (v instanceof NumericValue)
|
||||
if (v instanceof final NumericValue number)
|
||||
{
|
||||
String lstr = getString();
|
||||
return new StringValue(lstr.substring(0, (int)(lstr.length()/ ((NumericValue) v).getDouble())));
|
||||
final String lstr = getString();
|
||||
return new StringValue(lstr.substring(0, (int) (lstr.length() / number.getDouble())));
|
||||
}
|
||||
return new StringValue(getString()+"/"+v.getString());
|
||||
return new StringValue(getString() + "/" + v.getString());
|
||||
}
|
||||
|
||||
public Value()
|
||||
@@ -103,18 +110,18 @@ public abstract class Value implements Comparable<Value>, Cloneable
|
||||
@Override
|
||||
public int compareTo(final Value o)
|
||||
{
|
||||
if (o instanceof NumericValue || o instanceof ListValue || o instanceof ThreadValue)
|
||||
{
|
||||
return -o.compareTo(this);
|
||||
}
|
||||
return getString().compareTo(o.getString());
|
||||
return o instanceof NumericValue || o instanceof ListValue || o instanceof ThreadValue
|
||||
? -o.compareTo(this)
|
||||
: getString().compareTo(o.getString());
|
||||
}
|
||||
|
||||
@Override // for hashmap key access, and == operator
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (o instanceof Value)
|
||||
return this.compareTo((Value) o)==0;
|
||||
if (o instanceof final Value v)
|
||||
{
|
||||
return this.compareTo(v) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,50 +133,65 @@ public abstract class Value implements Comparable<Value>, Cloneable
|
||||
{
|
||||
throw new InternalExpressionException(boundVariable+ " cannot be assigned a new value");
|
||||
}*/
|
||||
throw new InternalExpressionException(getString()+ " is not a variable");
|
||||
|
||||
throw new InternalExpressionException(getString() + " is not a variable");
|
||||
}
|
||||
}
|
||||
|
||||
public Value in(Value value1)
|
||||
public Value in(final Value value1)
|
||||
{
|
||||
final Pattern p;
|
||||
try
|
||||
{
|
||||
p = Pattern.compile(value1.getString());
|
||||
}
|
||||
catch (PatternSyntaxException pse)
|
||||
catch (final PatternSyntaxException pse)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect matching pattern: "+pse.getMessage());
|
||||
throw new InternalExpressionException("Incorrect matching pattern: " + pse.getMessage());
|
||||
}
|
||||
final Matcher m = p.matcher(this.getString());
|
||||
if (!m.find()) return Value.NULL;
|
||||
int gc = m.groupCount();
|
||||
if (gc == 0) return new StringValue(m.group());
|
||||
if (gc == 1) return StringValue.of(m.group(1));
|
||||
List<Value> groups = new ArrayList<>(gc);
|
||||
if (!m.find())
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
final int gc = m.groupCount();
|
||||
if (gc == 0)
|
||||
{
|
||||
return new StringValue(m.group());
|
||||
}
|
||||
if (gc == 1)
|
||||
{
|
||||
return StringValue.of(m.group(1));
|
||||
}
|
||||
final List<Value> groups = new ArrayList<>(gc);
|
||||
for (int i = 1; i <= gc; i++)
|
||||
{
|
||||
groups.add(StringValue.of(m.group(i)));
|
||||
}
|
||||
return ListValue.wrap(groups);
|
||||
}
|
||||
|
||||
public int length()
|
||||
{
|
||||
return getString().length();
|
||||
}
|
||||
|
||||
public Value slice(long fromDesc, Long toDesc)
|
||||
public Value slice(final long fromDesc, final Long toDesc)
|
||||
{
|
||||
String value = this.getString();
|
||||
int size = value.length();
|
||||
int from = ListValue.normalizeIndex(fromDesc, size);
|
||||
if (toDesc == null) return new StringValue(value.substring(from));
|
||||
int to = ListValue.normalizeIndex(toDesc, size+1);
|
||||
if (from > to) return StringValue.EMPTY;
|
||||
final String value = this.getString();
|
||||
final int size = value.length();
|
||||
final int from = ListValue.normalizeIndex(fromDesc, size);
|
||||
if (toDesc == null)
|
||||
{
|
||||
return new StringValue(value.substring(from));
|
||||
}
|
||||
final int to = ListValue.normalizeIndex(toDesc, size + 1);
|
||||
if (from > to)
|
||||
{
|
||||
return StringValue.EMPTY;
|
||||
}
|
||||
return new StringValue(value.substring(from, to));
|
||||
}
|
||||
|
||||
|
||||
public Value split(Value delimiter)
|
||||
{
|
||||
if (delimiter == null)
|
||||
@@ -180,20 +202,20 @@ public abstract class Value implements Comparable<Value>, Cloneable
|
||||
{
|
||||
return ListValue.wrap(Arrays.stream(getString().split(delimiter.getString())).map(StringValue::new));
|
||||
}
|
||||
catch (PatternSyntaxException pse)
|
||||
catch (final PatternSyntaxException pse)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect pattern for 'split': "+pse.getMessage());
|
||||
throw new InternalExpressionException("Incorrect pattern for 'split': " + pse.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public double readDoubleNumber()
|
||||
{
|
||||
String s = getString();
|
||||
final String s = getString();
|
||||
try
|
||||
{
|
||||
return Double.valueOf(s);
|
||||
return Double.parseDouble(s);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
catch (final NumberFormatException e)
|
||||
{
|
||||
return Double.NaN;
|
||||
}
|
||||
@@ -212,21 +234,20 @@ public abstract class Value implements Comparable<Value>, Cloneable
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
String stringVal = getString();
|
||||
if (stringVal.isEmpty()) return 0;
|
||||
return ("s"+stringVal).hashCode();
|
||||
final String stringVal = getString();
|
||||
return stringVal.isEmpty() ? 0 : ("s" + stringVal).hashCode();
|
||||
}
|
||||
|
||||
public Value deepcopy()
|
||||
{
|
||||
try
|
||||
{
|
||||
return (Value)this.clone();
|
||||
return (Value) this.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
catch (final CloneNotSupportedException e)
|
||||
{
|
||||
// should never happen
|
||||
throw new InternalExpressionException("Cannot make a copy of value: "+this);
|
||||
throw new InternalExpressionException("Cannot make a copy of value: " + this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,12 +258,18 @@ public abstract class Value implements Comparable<Value>, Cloneable
|
||||
return new JsonPrimitive(getString());
|
||||
}
|
||||
|
||||
public boolean isNull() { return false; }
|
||||
public boolean isNull()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return retrieves useful in-run value of an optimized code-base value.
|
||||
* For immutable values (most of them) it can return itself,
|
||||
* but for mutables, it needs to be its copy or deep copy.
|
||||
*/
|
||||
public Value fromConstant() { return this; }
|
||||
public Value fromConstant()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.scores.Objective;
|
||||
import net.minecraft.world.scores.criteria.ObjectiveCriteria;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -60,58 +61,65 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
|
||||
public class ValueConversions
|
||||
{
|
||||
public static Value of(BlockPos pos)
|
||||
public static Value of(final BlockPos pos)
|
||||
{
|
||||
return ListValue.of(new NumericValue(pos.getX()), new NumericValue(pos.getY()), new NumericValue(pos.getZ()));
|
||||
}
|
||||
|
||||
public static Value of(Vec3 vec)
|
||||
public static Value of(final Vec3 vec)
|
||||
{
|
||||
return ListValue.of(new NumericValue(vec.x), new NumericValue(vec.y), new NumericValue(vec.z));
|
||||
}
|
||||
|
||||
public static Value of(ColumnPos cpos) { return ListValue.of(new NumericValue(cpos.x()), new NumericValue(cpos.z()));}
|
||||
public static Value of(final ColumnPos cpos)
|
||||
{
|
||||
return ListValue.of(new NumericValue(cpos.x()), new NumericValue(cpos.z()));
|
||||
}
|
||||
|
||||
public static Value of(ServerLevel world)
|
||||
public static Value of(final ServerLevel world)
|
||||
{
|
||||
return of(world.dimension().location());
|
||||
}
|
||||
|
||||
public static Value of(MaterialColor color) {return ListValue.of(StringValue.of(BlockInfo.mapColourName.get(color)), ofRGB(color.col));}
|
||||
public static Value of(final MaterialColor color)
|
||||
{
|
||||
return ListValue.of(StringValue.of(BlockInfo.mapColourName.get(color)), ofRGB(color.col));
|
||||
}
|
||||
|
||||
public static <T extends Number> Value of(MinMaxBounds<T> range) { return ListValue.of(NumericValue.of(range.getMin()), NumericValue.of(range.getMax()));}
|
||||
public static <T extends Number> Value of(final MinMaxBounds<T> range)
|
||||
{
|
||||
return ListValue.of(NumericValue.of(range.getMin()), NumericValue.of(range.getMax()));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Value of(ItemStack stack)
|
||||
public static Value of(final ItemStack stack)
|
||||
{
|
||||
if (stack == null || stack.isEmpty())
|
||||
return Value.NULL;
|
||||
return ListValue.of(
|
||||
return stack == null || stack.isEmpty() ? Value.NULL : ListValue.of(
|
||||
of(BuiltInRegistries.ITEM.getKey(stack.getItem())),
|
||||
new NumericValue(stack.getCount()),
|
||||
NBTSerializableValue.fromStack(stack)
|
||||
);
|
||||
}
|
||||
public static Value of(ItemStack stack, RegistryAccess regs) {
|
||||
if (stack == null || stack.isEmpty())
|
||||
return Value.NULL;
|
||||
return ListValue.of(
|
||||
|
||||
public static Value of(final ItemStack stack, final RegistryAccess regs)
|
||||
{
|
||||
return stack == null || stack.isEmpty() ? Value.NULL : ListValue.of(
|
||||
of(regs.registryOrThrow(Registries.ITEM).getKey(stack.getItem())),
|
||||
new NumericValue(stack.getCount()),
|
||||
NBTSerializableValue.fromStack(stack)
|
||||
);
|
||||
}
|
||||
|
||||
public static Value of(Objective objective)
|
||||
public static Value of(final Objective objective)
|
||||
{
|
||||
return ListValue.of(
|
||||
StringValue.of(objective.getName()),
|
||||
StringValue.of(objective.getCriteria().getName())
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static Value of(ObjectiveCriteria criteria)
|
||||
public static Value of(final ObjectiveCriteria criteria)
|
||||
{
|
||||
return ListValue.of(
|
||||
StringValue.of(criteria.getName()),
|
||||
@@ -120,20 +128,22 @@ public class ValueConversions
|
||||
}
|
||||
|
||||
|
||||
public static Value of(ParticleOptions particle)
|
||||
public static Value of(final ParticleOptions particle)
|
||||
{
|
||||
String repr = particle.writeToString();
|
||||
if (repr.startsWith("minecraft:")) return StringValue.of(repr.substring(10));
|
||||
return StringValue.of(repr);
|
||||
final String repr = particle.writeToString();
|
||||
return StringValue.of(repr.startsWith("minecraft:") ? repr.substring(10) : repr);
|
||||
}
|
||||
|
||||
public static Value ofRGB(int value) {return new NumericValue(value*256+255 );}
|
||||
public static Value ofRGB(final int value)
|
||||
{
|
||||
return new NumericValue(value * 256 + 255);
|
||||
}
|
||||
|
||||
public static Level dimFromValue(Value dimensionValue, MinecraftServer server)
|
||||
public static Level dimFromValue(final Value dimensionValue, final MinecraftServer server)
|
||||
{
|
||||
if (dimensionValue instanceof EntityValue)
|
||||
{
|
||||
return ((EntityValue)dimensionValue).getEntity().getCommandSenderWorld();
|
||||
return ((EntityValue) dimensionValue).getEntity().getCommandSenderWorld();
|
||||
}
|
||||
else if (dimensionValue instanceof BlockValue bv)
|
||||
{
|
||||
@@ -148,23 +158,16 @@ public class ValueConversions
|
||||
}
|
||||
else
|
||||
{
|
||||
String dimString = dimensionValue.getString().toLowerCase(Locale.ROOT);
|
||||
switch (dimString)
|
||||
{
|
||||
case "nether":
|
||||
case "the_nether":
|
||||
return server.getLevel(Level.NETHER);
|
||||
case "end":
|
||||
case "the_end":
|
||||
return server.getLevel(Level.END);
|
||||
case "overworld":
|
||||
case "over_world":
|
||||
return server.getLevel(Level.OVERWORLD);
|
||||
default:
|
||||
final String dimString = dimensionValue.getString().toLowerCase(Locale.ROOT);
|
||||
return switch (dimString) {
|
||||
case "nether", "the_nether" -> server.getLevel(Level.NETHER);
|
||||
case "end", "the_end" -> server.getLevel(Level.END);
|
||||
case "overworld", "over_world" -> server.getLevel(Level.OVERWORLD);
|
||||
default -> {
|
||||
ResourceKey<Level> dim = null;
|
||||
ResourceLocation id = new ResourceLocation(dimString);
|
||||
final ResourceLocation id = new ResourceLocation(dimString);
|
||||
// not using RegistryKey.of since that one creates on check
|
||||
for (ResourceKey<Level> world : (server.levelKeys()))
|
||||
for (final ResourceKey<Level> world : (server.levelKeys()))
|
||||
{
|
||||
if (id.equals(world.location()))
|
||||
{
|
||||
@@ -173,36 +176,48 @@ public class ValueConversions
|
||||
}
|
||||
}
|
||||
if (dim == null)
|
||||
{
|
||||
throw new ThrowStatement(dimString, Throwables.UNKNOWN_DIMENSION);
|
||||
return server.getLevel(dim);
|
||||
}
|
||||
}
|
||||
yield server.getLevel(dim);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static Value of(ResourceKey<?> dim)
|
||||
public static Value of(final ResourceKey<?> dim)
|
||||
{
|
||||
return of(dim.location());
|
||||
}
|
||||
|
||||
public static Value of(TagKey<?> tagKey) { return of(tagKey.location()); }
|
||||
public static Value of(final TagKey<?> tagKey)
|
||||
{
|
||||
return of(tagKey.location());
|
||||
}
|
||||
|
||||
public static Value of(ResourceLocation id)
|
||||
public static Value of(final ResourceLocation id)
|
||||
{
|
||||
if (id == null) // should be Value.NULL
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
return new StringValue(simplify(id));
|
||||
}
|
||||
|
||||
public static String simplify(ResourceLocation id)
|
||||
public static String simplify(final ResourceLocation id)
|
||||
{
|
||||
if (id == null) // should be Value.NULL
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if (id.getNamespace().equals("minecraft"))
|
||||
{
|
||||
return id.getPath();
|
||||
}
|
||||
return id.toString();
|
||||
}
|
||||
|
||||
public static Value of(GlobalPos pos)
|
||||
public static Value of(final GlobalPos pos)
|
||||
{
|
||||
return ListValue.of(
|
||||
ValueConversions.of(pos.dimension()),
|
||||
@@ -210,14 +225,13 @@ public class ValueConversions
|
||||
);
|
||||
}
|
||||
|
||||
public static Value fromPath(ServerLevel world, Path path)
|
||||
public static Value fromPath(final ServerLevel world, final Path path)
|
||||
{
|
||||
List<Value> nodes = new ArrayList<>();
|
||||
//for (PathNode node: path.getNodes())
|
||||
final List<Value> nodes = new ArrayList<>();
|
||||
for (int i = 0, len = path.getNodeCount(); i < len; i++)
|
||||
{
|
||||
Node node = path.getNode(i);
|
||||
nodes.add( ListValue.of(
|
||||
final Node node = path.getNode(i);
|
||||
nodes.add(ListValue.of(
|
||||
new BlockValue(null, world, node.asBlockPos()),
|
||||
new StringValue(node.type.name().toLowerCase(Locale.ROOT)),
|
||||
new NumericValue(node.costMalus),
|
||||
@@ -227,101 +241,106 @@ public class ValueConversions
|
||||
return ListValue.wrap(nodes);
|
||||
}
|
||||
|
||||
public static Value fromTimedMemory(Entity e, long expiry, Object v)
|
||||
public static Value fromTimedMemory(final Entity e, final long expiry, final Object v)
|
||||
{
|
||||
Value ret = fromEntityMemory(e, v);
|
||||
if (ret.isNull() || expiry == Long.MAX_VALUE) return ret;
|
||||
return ListValue.of(ret, new NumericValue(expiry));
|
||||
final Value ret = fromEntityMemory(e, v);
|
||||
return ret.isNull() || expiry == Long.MAX_VALUE ? ret : ListValue.of(ret, new NumericValue(expiry));
|
||||
}
|
||||
|
||||
private static Value fromEntityMemory(Entity e, Object v)
|
||||
private static Value fromEntityMemory(final Entity e, Object v)
|
||||
{
|
||||
if (v instanceof GlobalPos pos)
|
||||
{
|
||||
return of(pos);
|
||||
}
|
||||
if (v instanceof Entity)
|
||||
if (v instanceof final Entity entity)
|
||||
{
|
||||
return new EntityValue((Entity)v);
|
||||
return new EntityValue(entity);
|
||||
}
|
||||
if (v instanceof BlockPos)
|
||||
if (v instanceof final BlockPos pos)
|
||||
{
|
||||
return new BlockValue(null, (ServerLevel) e.getCommandSenderWorld(), (BlockPos) v);
|
||||
return new BlockValue(null, e.getCommandSenderWorld(), pos);
|
||||
}
|
||||
if (v instanceof Number)
|
||||
if (v instanceof final Number number)
|
||||
{
|
||||
return new NumericValue(((Number) v).doubleValue());
|
||||
return new NumericValue(number.doubleValue());
|
||||
}
|
||||
if (v instanceof Boolean)
|
||||
if (v instanceof final Boolean bool)
|
||||
{
|
||||
return BooleanValue.of((Boolean) v);
|
||||
return BooleanValue.of(bool);
|
||||
}
|
||||
if (v instanceof UUID)
|
||||
if (v instanceof final UUID uuid)
|
||||
{
|
||||
return ofUUID( (ServerLevel) e.getCommandSenderWorld(), (UUID)v);
|
||||
return ofUUID((ServerLevel) e.getCommandSenderWorld(), uuid);
|
||||
}
|
||||
if (v instanceof DamageSource source)
|
||||
if (v instanceof final DamageSource source)
|
||||
{
|
||||
return ListValue.of(
|
||||
new StringValue(source.getMsgId()),
|
||||
source.getEntity()==null?Value.NULL:new EntityValue(source.getEntity())
|
||||
source.getEntity() == null ? Value.NULL : new EntityValue(source.getEntity())
|
||||
);
|
||||
}
|
||||
if (v instanceof Path)
|
||||
if (v instanceof final Path path)
|
||||
{
|
||||
return fromPath((ServerLevel)e.getCommandSenderWorld(), (Path)v);
|
||||
return fromPath((ServerLevel) e.getCommandSenderWorld(), path);
|
||||
}
|
||||
if (v instanceof PositionTracker)
|
||||
if (v instanceof final PositionTracker tracker)
|
||||
{
|
||||
return new BlockValue(null, e.getCommandSenderWorld(), ((PositionTracker)v).currentBlockPosition());
|
||||
return new BlockValue(null, e.getCommandSenderWorld(), tracker.currentBlockPosition());
|
||||
}
|
||||
if (v instanceof WalkTarget)
|
||||
if (v instanceof final WalkTarget target)
|
||||
{
|
||||
return ListValue.of(
|
||||
new BlockValue(null, e.getCommandSenderWorld(), ((WalkTarget)v).getTarget().currentBlockPosition()),
|
||||
new NumericValue(((WalkTarget) v).getSpeedModifier()),
|
||||
new NumericValue(((WalkTarget) v).getCloseEnoughDist())
|
||||
new BlockValue(null, e.getCommandSenderWorld(), target.getTarget().currentBlockPosition()),
|
||||
new NumericValue(target.getSpeedModifier()),
|
||||
new NumericValue(target.getCloseEnoughDist())
|
||||
);
|
||||
}
|
||||
if (v instanceof NearestVisibleLivingEntities nvle) {
|
||||
if (v instanceof final NearestVisibleLivingEntities nvle)
|
||||
{
|
||||
v = StreamSupport.stream(nvle.findAll(entity -> true).spliterator(), false).toList();
|
||||
}
|
||||
if (v instanceof Set)
|
||||
if (v instanceof final Set<?> set)
|
||||
{
|
||||
v = new ArrayList<>(((Set<?>) v));
|
||||
v = new ArrayList<>(set);
|
||||
}
|
||||
if (v instanceof List<?> l)
|
||||
if (v instanceof final List<?> l)
|
||||
{
|
||||
if (l.isEmpty()) return ListValue.of();
|
||||
Object el = l.get(0);
|
||||
if (el instanceof Entity)
|
||||
if (l.isEmpty())
|
||||
{
|
||||
return ListValue.wrap(l.stream().map(o -> new EntityValue((Entity)o)));
|
||||
return ListValue.of();
|
||||
}
|
||||
if (el instanceof GlobalPos)
|
||||
final Object el = l.get(0);
|
||||
if (el instanceof final Entity entity)
|
||||
{
|
||||
return ListValue.wrap(l.stream().map(o -> of((GlobalPos) o)));
|
||||
return ListValue.wrap(l.stream().map(o -> new EntityValue(entity)));
|
||||
}
|
||||
if (el instanceof final GlobalPos pos)
|
||||
{
|
||||
return ListValue.wrap(l.stream().map(o -> of(pos)));
|
||||
}
|
||||
}
|
||||
return Value.NULL;
|
||||
}
|
||||
|
||||
private static Value ofUUID(ServerLevel entityWorld, UUID uuid)
|
||||
private static Value ofUUID(final ServerLevel entityWorld, final UUID uuid)
|
||||
{
|
||||
Entity current = entityWorld.getEntity(uuid);
|
||||
final Entity current = entityWorld.getEntity(uuid);
|
||||
return ListValue.of(
|
||||
current == null?Value.NULL:new EntityValue(current),
|
||||
current == null ? Value.NULL : new EntityValue(current),
|
||||
new StringValue(uuid.toString())
|
||||
);
|
||||
}
|
||||
public static Value of(AABB box)
|
||||
|
||||
public static Value of(final AABB box)
|
||||
{
|
||||
return ListValue.of(
|
||||
ListValue.fromTriple(box.minX, box.minY, box.minZ),
|
||||
ListValue.fromTriple(box.maxX, box.maxY, box.maxZ)
|
||||
);
|
||||
}
|
||||
public static Value of(BoundingBox box)
|
||||
|
||||
public static Value of(final BoundingBox box)
|
||||
{
|
||||
return ListValue.of(
|
||||
ListValue.fromTriple(box.minX(), box.minY(), box.minZ()),
|
||||
@@ -329,17 +348,23 @@ public class ValueConversions
|
||||
);
|
||||
}
|
||||
|
||||
public static Value of(StructureStart structure, final RegistryAccess regs)
|
||||
public static Value of(final StructureStart structure, final RegistryAccess regs)
|
||||
{
|
||||
if (structure == null || structure == StructureStart.INVALID_START) return Value.NULL;
|
||||
BoundingBox boundingBox = structure.getBoundingBox();
|
||||
if (boundingBox.maxX() < boundingBox.minX() || boundingBox.maxY() < boundingBox.minY() || boundingBox.maxZ() < boundingBox.minZ()) return Value.NULL;
|
||||
Map<Value, Value> ret = new HashMap<>();
|
||||
ret.put(new StringValue("box"), of(boundingBox));
|
||||
List<Value> pieces = new ArrayList<>();
|
||||
for (StructurePiece piece : structure.getPieces())
|
||||
if (structure == null || structure == StructureStart.INVALID_START)
|
||||
{
|
||||
BoundingBox box = piece.getBoundingBox();
|
||||
return Value.NULL;
|
||||
}
|
||||
final BoundingBox boundingBox = structure.getBoundingBox();
|
||||
if (boundingBox.maxX() < boundingBox.minX() || boundingBox.maxY() < boundingBox.minY() || boundingBox.maxZ() < boundingBox.minZ())
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
final Map<Value, Value> ret = new HashMap<>();
|
||||
ret.put(new StringValue("box"), of(boundingBox));
|
||||
final List<Value> pieces = new ArrayList<>();
|
||||
for (final StructurePiece piece : structure.getPieces())
|
||||
{
|
||||
final BoundingBox box = piece.getBoundingBox();
|
||||
if (box.maxX() >= box.minX() && box.maxY() >= box.minY() && box.maxZ() >= box.minZ())
|
||||
{
|
||||
pieces.add(ListValue.of(
|
||||
@@ -354,41 +379,51 @@ public class ValueConversions
|
||||
return MapValue.wrap(ret);
|
||||
}
|
||||
|
||||
public static Value fromProperty(BlockState state, Property<?> p)
|
||||
public static Value fromProperty(final BlockState state, final Property<?> p)
|
||||
{
|
||||
Comparable<?> object = state.getValue(p);
|
||||
if (object instanceof Boolean || object instanceof Number) return StringValue.of(object.toString());
|
||||
if (object instanceof StringRepresentable)
|
||||
final Comparable<?> object = state.getValue(p);
|
||||
if (object instanceof Boolean || object instanceof Number)
|
||||
{
|
||||
return StringValue.of(((StringRepresentable) object).getSerializedName());
|
||||
return StringValue.of(object.toString());
|
||||
}
|
||||
throw new InternalExpressionException("Unknown property type: "+p.getName());
|
||||
if (object instanceof final StringRepresentable stringRepresentable)
|
||||
{
|
||||
return StringValue.of(stringRepresentable.getSerializedName());
|
||||
}
|
||||
throw new InternalExpressionException("Unknown property type: " + p.getName());
|
||||
}
|
||||
|
||||
record SlotParam(/* Nullable */ String type, int id) {
|
||||
public ListValue build() {
|
||||
record SlotParam(/* Nullable */ String type, int id)
|
||||
{
|
||||
public ListValue build()
|
||||
{
|
||||
return ListValue.of(StringValue.of(type), new NumericValue(id));
|
||||
}
|
||||
}
|
||||
|
||||
private static final Int2ObjectMap<SlotParam> slotIdsToSlotParams = new Int2ObjectOpenHashMap<>() {{
|
||||
private static final Int2ObjectMap<SlotParam> slotIdsToSlotParams = new Int2ObjectOpenHashMap<>()
|
||||
{{
|
||||
int n;
|
||||
//covers blocks, player hotbar and inventory, and all default inventories
|
||||
for(n = 0; n < 54; ++n) {
|
||||
for (n = 0; n < 54; ++n)
|
||||
{
|
||||
put(n, new SlotParam(null, n));
|
||||
}
|
||||
for(n = 0; n < 27; ++n) {
|
||||
for (n = 0; n < 27; ++n)
|
||||
{
|
||||
put(200 + n, new SlotParam("enderchest", n));
|
||||
}
|
||||
|
||||
// villager
|
||||
for(n = 0; n < 8; ++n) {
|
||||
for (n = 0; n < 8; ++n)
|
||||
{
|
||||
put(300 + n, new SlotParam(null, n));
|
||||
}
|
||||
|
||||
// horse, llamas, donkeys, etc.
|
||||
// two first slots are for saddle and armour
|
||||
for(n = 0; n < 15; ++n) {
|
||||
for (n = 0; n < 15; ++n)
|
||||
{
|
||||
put(500 + n, new SlotParam(null, n + 2));
|
||||
}
|
||||
// weapon main hand
|
||||
@@ -396,7 +431,8 @@ public class ValueConversions
|
||||
// offhand
|
||||
put(99, new SlotParam("equipment", 5));
|
||||
// feet, legs, chest, head
|
||||
for(n = 0; n < 4; ++n) {
|
||||
for (n = 0; n < 4; ++n)
|
||||
{
|
||||
put(100 + n, new SlotParam("equipment", n + 1));
|
||||
}
|
||||
//horse defaults saddle
|
||||
@@ -407,26 +443,25 @@ public class ValueConversions
|
||||
//hashMap.put("horse.chest", 499);
|
||||
}};
|
||||
|
||||
public static Value ofVanillaSlotResult(int itemSlot)
|
||||
public static Value ofVanillaSlotResult(final int itemSlot)
|
||||
{
|
||||
SlotParam ret = slotIdsToSlotParams.get(itemSlot);
|
||||
if (ret == null) return ListValue.of(Value.NULL, new NumericValue(itemSlot));
|
||||
return ret.build();
|
||||
final SlotParam ret = slotIdsToSlotParams.get(itemSlot);
|
||||
return ret == null ? ListValue.of(Value.NULL, new NumericValue(itemSlot)) : ret.build();
|
||||
}
|
||||
|
||||
public static Value ofBlockPredicate(RegistryAccess registryAccess, Predicate<BlockInWorld> blockPredicate)
|
||||
public static Value ofBlockPredicate(final RegistryAccess registryAccess, final Predicate<BlockInWorld> blockPredicate)
|
||||
{
|
||||
BlockPredicateInterface predicateData = (BlockPredicateInterface) blockPredicate;
|
||||
final BlockPredicateInterface predicateData = (BlockPredicateInterface) blockPredicate;
|
||||
final Registry<Block> blocks = registryAccess.registryOrThrow(Registries.BLOCK);
|
||||
return ListValue.of(
|
||||
predicateData.getCMBlockState()==null?Value.NULL:of(blocks.getKey(predicateData.getCMBlockState().getBlock())),
|
||||
predicateData.getCMBlockTagKey()==null?Value.NULL:of(blocks.getTag(predicateData.getCMBlockTagKey()).get().key()),
|
||||
predicateData.getCMBlockState() == null ? Value.NULL : of(blocks.getKey(predicateData.getCMBlockState().getBlock())),
|
||||
predicateData.getCMBlockTagKey() == null ? Value.NULL : of(blocks.getTag(predicateData.getCMBlockTagKey()).get().key()),
|
||||
MapValue.wrap(predicateData.getCMProperties()),
|
||||
predicateData.getCMDataTag() == null?Value.NULL:new NBTSerializableValue(predicateData.getCMDataTag())
|
||||
predicateData.getCMDataTag() == null ? Value.NULL : new NBTSerializableValue(predicateData.getCMDataTag())
|
||||
);
|
||||
}
|
||||
|
||||
public static ItemStack getItemStackFromValue(Value value, boolean withCount, RegistryAccess regs)
|
||||
public static ItemStack getItemStackFromValue(final Value value, final boolean withCount, final RegistryAccess regs)
|
||||
{
|
||||
if (value.isNull())
|
||||
{
|
||||
@@ -439,7 +474,7 @@ public class ValueConversions
|
||||
{
|
||||
if (list.length() != 3)
|
||||
{
|
||||
throw new ThrowStatement("item definition from list of size "+list.length(), Throwables.UNKNOWN_ITEM);
|
||||
throw new ThrowStatement("item definition from list of size " + list.length(), Throwables.UNKNOWN_ITEM);
|
||||
}
|
||||
final List<Value> items = list.getItems();
|
||||
name = items.get(0).getString();
|
||||
@@ -447,7 +482,7 @@ public class ValueConversions
|
||||
{
|
||||
count = NumericValue.asNumber(items.get(1)).getInt();
|
||||
}
|
||||
Value nbtValue = items.get(2);
|
||||
final Value nbtValue = items.get(2);
|
||||
if (!nbtValue.isNull())
|
||||
{
|
||||
nbtTag = ((NBTSerializableValue) NBTSerializableValue.fromValue(nbtValue)).getCompoundTag();
|
||||
@@ -457,12 +492,12 @@ public class ValueConversions
|
||||
{
|
||||
name = value.getString();
|
||||
}
|
||||
ItemInput itemInput = NBTSerializableValue.parseItem(name, nbtTag, regs);
|
||||
final ItemInput itemInput = NBTSerializableValue.parseItem(name, nbtTag, regs);
|
||||
try
|
||||
{
|
||||
return itemInput.createItemStack(count,false);
|
||||
return itemInput.createItemStack(count, false);
|
||||
}
|
||||
catch (CommandSyntaxException cse)
|
||||
catch (final CommandSyntaxException cse)
|
||||
{
|
||||
if (!withCount)
|
||||
{
|
||||
@@ -475,31 +510,56 @@ public class ValueConversions
|
||||
}
|
||||
}
|
||||
|
||||
public static Value guess(ServerLevel serverWorld, Object o) {
|
||||
public static Value guess(final ServerLevel serverWorld, final Object o)
|
||||
{
|
||||
if (o == null)
|
||||
{
|
||||
return Value.NULL;
|
||||
if (o instanceof List)
|
||||
return ListValue.wrap(((List<?>) o).stream().map(oo -> guess(serverWorld, oo)));
|
||||
if (o instanceof BlockPos)
|
||||
return new BlockValue(null, serverWorld, (BlockPos)o);
|
||||
if (o instanceof Entity)
|
||||
return EntityValue.of((Entity) o);
|
||||
if (o instanceof Vec3)
|
||||
return of((Vec3)o);
|
||||
if (o instanceof Vec3i)
|
||||
return of(new BlockPos((Vec3i)o));
|
||||
if (o instanceof AABB)
|
||||
return of((AABB)o);
|
||||
if (o instanceof BoundingBox)
|
||||
return of((BoundingBox) o);
|
||||
if (o instanceof ItemStack)
|
||||
return of((ItemStack)o, serverWorld.registryAccess());
|
||||
if (o instanceof Boolean)
|
||||
return BooleanValue.of((Boolean) o);
|
||||
if (o instanceof Number)
|
||||
return NumericValue.of((Number) o);
|
||||
if (o instanceof ResourceLocation)
|
||||
return of((ResourceLocation)o);
|
||||
}
|
||||
if (o instanceof final List<?> list)
|
||||
{
|
||||
return ListValue.wrap(list.stream().map(oo -> guess(serverWorld, oo)));
|
||||
}
|
||||
if (o instanceof final BlockPos pos)
|
||||
{
|
||||
return new BlockValue(null, serverWorld, pos);
|
||||
}
|
||||
if (o instanceof final Entity e)
|
||||
{
|
||||
return EntityValue.of(e);
|
||||
}
|
||||
if (o instanceof final Vec3 vec3)
|
||||
{
|
||||
return of(vec3);
|
||||
}
|
||||
if (o instanceof final Vec3i vec3i)
|
||||
{
|
||||
return of(new BlockPos(vec3i));
|
||||
}
|
||||
if (o instanceof final AABB aabb)
|
||||
{
|
||||
return of(aabb);
|
||||
}
|
||||
if (o instanceof final BoundingBox bb)
|
||||
{
|
||||
return of(bb);
|
||||
}
|
||||
if (o instanceof final ItemStack itemStack)
|
||||
{
|
||||
return of(itemStack, serverWorld.registryAccess());
|
||||
}
|
||||
if (o instanceof final Boolean bool)
|
||||
{
|
||||
return BooleanValue.of(bool);
|
||||
}
|
||||
if (o instanceof final Number number)
|
||||
{
|
||||
return NumericValue.of(number);
|
||||
}
|
||||
if (o instanceof final ResourceLocation resourceLocation)
|
||||
{
|
||||
return of(resourceLocation);
|
||||
}
|
||||
return StringValue.of(o.toString());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user