Merge branch 'master' into light

# Conflicts:
#	src/main/resources/carpet.accesswidener
#	src/main/resources/fabric.mod.json
This commit is contained in:
gnembon committed 2020-07-01 00:11:35 -03:00
commit 7067e59a21
66 files changed
+1898 -495

No files matched your search

@@ -488,6 +488,37 @@ public class CarpetEventServer
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
},
PLAYER_CHOOSES_RECIPE("player_chooses_recipe", 3, false)
{
@Override
public void onRecipeSelected(ServerPlayerEntity player, Identifier recipe, boolean fullStack)
{
handler.call( () ->
{
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new StringValue(NBTSerializableValue.nameFromRegistryId(recipe))),
((c, t) -> new NumericValue(fullStack))
);
}, player::getCommandSource);
}
},
PLAYER_SWITCHES_SLOT("player_switches_slot", 3, false)
{
@Override
public void onSlotSwitch(ServerPlayerEntity player, int from, int to)
{
if (from == to) return; // initial slot update
handler.call( () ->
{
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new NumericValue(from)),
((c, t) -> new NumericValue(to))
);
}, player::getCommandSource);
}
},
PLAYER_TAKES_DAMAGE("player_takes_damage", 4, false)
{
@Override
@@ -647,6 +678,8 @@ public class CarpetEventServer
public void onEntityAction(ServerPlayerEntity player, Entity entity, Hand enumhand) { }
public void onDimensionChange(ServerPlayerEntity player, Vec3d from, Vec3d to, DimensionType fromDim, DimensionType dimTo) {}
public void onDamage(Entity target, float amount, DamageSource source) { }
public void onRecipeSelected(ServerPlayerEntity player, Identifier recipe, boolean fullStack) {}
public void onSlotSwitch(ServerPlayerEntity player, int from, int to) {}
public void onWorldEvent(ServerWorld world, BlockPos pos) { }
+344 -111
View File
@@ -2,8 +2,10 @@ package carpet.script;
import carpet.CarpetServer;
import carpet.fakes.ChunkTicketManagerInterface;
import carpet.fakes.IngredientInterface;
import carpet.fakes.MinecraftServerInterface;
import carpet.fakes.BiomeArrayInterface;
import carpet.fakes.RecipeManagerInterface;
import carpet.fakes.ServerChunkManagerInterface;
import carpet.fakes.ServerLightingProviderInterface;
import carpet.fakes.StatTypeInterface;
@@ -81,6 +83,13 @@ import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.recipe.AbstractCookingRecipe;
import net.minecraft.recipe.CuttingRecipe;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeType;
import net.minecraft.recipe.ShapedRecipe;
import net.minecraft.recipe.ShapelessRecipe;
import net.minecraft.recipe.SpecialCraftingRecipe;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.scoreboard.ScoreboardCriterion;
import net.minecraft.scoreboard.ScoreboardObjective;
@@ -97,6 +106,7 @@ import net.minecraft.stat.Stat;
import net.minecraft.stat.StatType;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.Property;
import net.minecraft.structure.StructureFeatures;
import net.minecraft.structure.StructurePiece;
import net.minecraft.structure.StructureStart;
import net.minecraft.text.LiteralText;
@@ -111,9 +121,11 @@ import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.EulerAngle;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.StructureFeature;
import net.minecraft.world.poi.PointOfInterest;
@@ -130,8 +142,10 @@ import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.ChunkRandom;
import org.apache.commons.lang3.tuple.Pair;
import java.util.Date;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -342,6 +356,18 @@ public class CarpetExpression
return MapValue.wrap(ret);
}
private static long lastSeed = -1;
private void BooYah(ChunkGenerator generator)
{
synchronized (generator)
{
if (generator.getSeed() != lastSeed)
{
StructureFeatures.STRONGHOLD.shouldStartAt(null, generator, null, 0, 0, null);
lastSeed = generator.getSeed();
}
}
}
private void API_BlockManipulation()
{
this.expr.addLazyFunction("block", -1, (c, t, lv) ->
@@ -737,43 +763,76 @@ public class CarpetExpression
this.expr.addLazyFunction("without_updates", 1, (c, t, lv) ->
{
boolean previous = CarpetSettings.impendingFillSkipUpdates;
try
if (previous) return lv.get(0);
Value [] result = new Value[]{Value.NULL};
((CarpetContext)c).s.getMinecraftServer().submitAndJoin( () ->
{
CarpetSettings.impendingFillSkipUpdates = true;
Value ret = lv.get(0).evalValue(c, t);
return (cc, tt) -> ret;
}
finally
{
CarpetSettings.impendingFillSkipUpdates = previous;
}
try
{
CarpetSettings.impendingFillSkipUpdates = true;
result[0] = lv.get(0).evalValue(c, t);
}
finally
{
CarpetSettings.impendingFillSkipUpdates = previous;
}
});
return (cc, tt) -> result[0];
});
this.expr.addLazyFunction("set", -1, (c, t, lv) ->
{
CarpetContext cc = (CarpetContext)c;
ServerWorld world = cc.s.getWorld();
if (lv.size() < 2 || lv.size() % 2 == 1)
throw new InternalExpressionException("'set' should have at least 2 params and odd attributes");
BlockArgument targetLocator = BlockArgument.findIn(cc, lv, 0);
BlockArgument sourceLocator = BlockArgument.findIn(cc, lv, targetLocator.offset, true);
BlockState sourceBlockState = sourceLocator.block.getBlockState();
BlockState targetBlockState = world.getBlockState(targetLocator.block.getPos());
if (sourceLocator.offset < lv.size())
CompoundTag data = null;
if (lv.size() > sourceLocator.offset)
{
StateManager<Block, BlockState> states = sourceBlockState.getBlock().getStateManager();
for (int i = sourceLocator.offset; i < lv.size(); i += 2)
List<Value> args = new ArrayList<>();
for (int i = sourceLocator.offset, m = lv.size(); i < m; i++)
{
String paramString = lv.get(i).evalValue(c).getString();
args.add(lv.get(i).evalValue(c));
}
if (args.get(0) instanceof ListValue)
{
if (args.size() == 2)
{
Value dataValue = NBTSerializableValue.fromValue( args.get(1));
if (dataValue instanceof NBTSerializableValue)
{
data = ((NBTSerializableValue) dataValue).getCompoundTag();
}
}
args = ((ListValue) args.get(0)).getItems();
}
else
{
if ((args.size() & 1) == 1)
{
Value dataValue = NBTSerializableValue.fromValue( args.get(args.size()-1));
if (dataValue instanceof NBTSerializableValue)
{
data = ((NBTSerializableValue) dataValue).getCompoundTag();
}
}
}
StateManager<Block, BlockState> states = sourceBlockState.getBlock().getStateManager();
for (int i = 0; i < args.size()-1; i += 2)
{
String paramString = args.get(i).getString();
Property<?> property = states.getProperty(paramString);
if (property == null)
throw new InternalExpressionException("Property " + paramString + " doesn't apply to " + sourceLocator.block.getString());
String paramValue = lv.get(i + 1).evalValue(c).getString();
String paramValue = args.get(i + 1).getString();
sourceBlockState = setProperty(property, paramString, paramValue, sourceBlockState);
}
}
CompoundTag data = sourceLocator.block.getData();
if (data == null) data = sourceLocator.block.getData();
CompoundTag finalData = data;
if (sourceBlockState == targetBlockState && data == null)
return (c_, t_) -> Value.FALSE;
@@ -783,12 +842,12 @@ public class CarpetExpression
{
Clearable.clear(world.getBlockEntity(targetPos));
world.setBlockState(targetPos, finalSourceBlockState, 2);
if (data != null)
if (finalData != null)
{
BlockEntity be = world.getBlockEntity(targetPos);
if (be != null)
{
CompoundTag destTag = data.copy();
CompoundTag destTag = finalData.copy();
destTag.putInt("x", targetPos.getX());
destTag.putInt("y", targetPos.getY());
destTag.putInt("z", targetPos.getZ());
@@ -897,7 +956,7 @@ public class CarpetExpression
Tag outtag = tool.getTag();
if (outtag == null)
return LazyValue.TRUE;
Value ret = new NBTSerializableValue(outtag);
Value ret = new NBTSerializableValue(() -> outtag);
return (_c, _t) -> ret;
});
@@ -1096,6 +1155,9 @@ public class CarpetExpression
BlockArgument locator = BlockArgument.findIn(cc, lv, 0);
ServerWorld world = cc.s.getWorld();
BooYah(world.getChunkManager().getChunkGenerator());
BlockPos pos = locator.block.getPos();
StructureFeature<?> structure = null;
boolean needSize = false;
@@ -1385,13 +1447,14 @@ public class CarpetExpression
});
this.expr.addLazyFunction("scoreboard_remove", -1, (c, t, lv)-> {
if (lv.size()==0) throw new InternalExpressionException("'scoreboard_remove' requires at least one parameter");
CarpetContext cc = (CarpetContext)c;
Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
String objectiveName = lv.get(0).evalValue(c).getString();
ScoreboardObjective objective = scoreboard.getObjective(objectiveName);
if (objective == null)
return LazyValue.FALSE;
if (lv.size() == 0)
if (lv.size() == 1)
{
scoreboard.removeObjective(objective);
return LazyValue.TRUE;
@@ -1472,6 +1535,120 @@ public class CarpetExpression
return (_c, _t) -> res;
});
this.expr.addLazyFunction("recipe_data", -1, (c, t, lv) ->
{
CarpetContext cc = (CarpetContext)c;
if (lv.size() < 1) throw new InternalExpressionException("'recipe_data' requires at least one argument");
String recipeName = lv.get(0).evalValue(c).getString();
RecipeType type = RecipeType.CRAFTING;
if (lv.size() > 1)
{
String recipeType = lv.get(1).evalValue(c).getString();
try
{
type = Registry.RECIPE_TYPE.get(new Identifier(recipeType));
}
catch (InvalidIdentifierException ignored)
{
throw new InternalExpressionException("Unknown crafting category: " + recipeType);
}
}
List<Recipe<?>> recipes;
try
{
recipes = ((RecipeManagerInterface) cc.s.getMinecraftServer().getRecipeManager()).getAllMatching(type, new Identifier(recipeName));
}
catch (InvalidIdentifierException ignored)
{
return LazyValue.NULL;
}
if (recipes.isEmpty())
return LazyValue.NULL;
List<Value> recipesOutput = new ArrayList<>();
for (Recipe<?> recipe: recipes)
{
ItemStack result = recipe.getOutput();
List<Value> ingredientValue = new ArrayList<>();
recipe.getPreviewInputs().forEach(
ingredient ->
{
// I am flattening ingredient lists per slot.
// consider recipe_data('wooden_sword','crafting') and ('iron_nugget', 'blasting') and notice difference
// in depths of lists.
List<Collection<ItemStack>> stacks = ((IngredientInterface) (Object) ingredient).getRecipeStacks();
if (stacks.isEmpty())
{
ingredientValue.add(Value.NULL);
}
else
{
List<Value> alternatives = new ArrayList<>();
stacks.forEach(col -> col.stream().map(ListValue::fromItemStack).forEach(alternatives::add));
ingredientValue.add(ListValue.wrap(alternatives));
}
}
);
Value recipeSpec;
if (recipe instanceof ShapedRecipe)
{
recipeSpec = ListValue.of(
new StringValue("shaped"),
new NumericValue(((ShapedRecipe) recipe).getWidth()),
new NumericValue(((ShapedRecipe) recipe).getHeight())
);
}
else if (recipe instanceof ShapelessRecipe)
{
recipeSpec = ListValue.of(new StringValue("shapeless"));
}
else if (recipe instanceof AbstractCookingRecipe)
{
recipeSpec = ListValue.of(
new StringValue("smelting"),
new NumericValue(((AbstractCookingRecipe) recipe).getCookTime()),
new NumericValue(((AbstractCookingRecipe) recipe).getExperience())
);
}
else if (recipe instanceof CuttingRecipe)
{
recipeSpec = ListValue.of(new StringValue("cutting"));
}
else if (recipe instanceof SpecialCraftingRecipe)
{
recipeSpec = ListValue.of(new StringValue("special"));
}
else
{
recipeSpec = ListValue.of(new StringValue("custom"));
}
recipesOutput.add(ListValue.of(ListValue.fromItemStack(result), ListValue.wrap(ingredientValue), recipeSpec));
}
Value ret = ListValue.wrap(recipesOutput);
return (_c, _t) -> ret;
});
this.expr.addLazyFunction("crafting_remaining_item", 1, (c, t, lv) ->
{
String itemStr = lv.get(0).evalValue(c).getString();
Item item;
try
{
Identifier id = new Identifier(itemStr);
item = Registry.ITEM.get(id);
if (item == Items.AIR && !id.getPath().equalsIgnoreCase("air"))
throw new InvalidIdentifierException("boo");
}
catch (InvalidIdentifierException ignored)
{
throw new InternalExpressionException("Incorrect item: "+itemStr);
}
if (!item.hasRecipeRemainder()) return LazyValue.NULL;
Value ret = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.ITEM.getId(item.getRecipeRemainder())));
return (_c, _t ) -> ret;
});
this.expr.addLazyFunction("inventory_size", -1, (c, t, lv) ->
{
CarpetContext cc = (CarpetContext) c;
@@ -1825,11 +2002,9 @@ public class CarpetExpression
Value nbt = lv.get(position.offset).evalValue(c);
NBTSerializableValue v = (nbt instanceof NBTSerializableValue) ? (NBTSerializableValue) nbt
: NBTSerializableValue.parseString(nbt.getString());
if (v != null)
{
hasTag = true;
tag = v.getCompoundTag();
}
hasTag = true;
tag = v.getCompoundTag();
}
tag.putString("id", entityId.toString());
Vec3d vec3d = position.vec;
@@ -2097,21 +2272,28 @@ public class CarpetExpression
return (c_, t_) -> new NumericValue(finalSCount);
});
this.expr.addLazyFunction("volume", 7, (c, t, lv) ->
this.expr.addLazyFunction("volume", -1, (c, t, lv) ->
{
int xi = (int) NumericValue.asNumber(lv.get(0).evalValue(c)).getLong();
int yi = (int) NumericValue.asNumber(lv.get(1).evalValue(c)).getLong();
int zi = (int) NumericValue.asNumber(lv.get(2).evalValue(c)).getLong();
int xj = (int) NumericValue.asNumber(lv.get(3).evalValue(c)).getLong();
int yj = (int) NumericValue.asNumber(lv.get(4).evalValue(c)).getLong();
int zj = (int) NumericValue.asNumber(lv.get(5).evalValue(c)).getLong();
int minx = min(xi, xj);
int miny = min(yi, yj);
int minz = min(zi, zj);
int maxx = max(xi, xj);
int maxy = max(yi, yj);
int maxz = max(zi, zj);
LazyValue expr = lv.get(6);
CarpetContext cc = (CarpetContext)c;
BlockArgument pos1Locator = BlockArgument.findIn(cc, lv, 0);
BlockArgument pos2Locator = BlockArgument.findIn(cc, lv, pos1Locator.offset);
BlockPos pos1 = pos1Locator.block.getPos();
BlockPos pos2 = pos2Locator.block.getPos();
int x1 = pos1.getX();
int y1 = pos1.getY();
int z1 = pos1.getZ();
int x2 = pos2.getX();
int y2 = pos2.getY();
int z2 = pos2.getZ();
int minx = min(x1, x2);
int miny = min(y1, y2);
int minz = min(z1, z2);
int maxx = max(x1, x2);
int maxy = max(y1, y2);
int maxz = max(z1, z2);
LazyValue expr = lv.get(pos2Locator.offset);
//saving outer scope
LazyValue _x = c.getVariable("_x");
@@ -2181,57 +2363,63 @@ public class CarpetExpression
this.expr.addLazyFunction("rect", -1, (c, t, lv)->
{
if (lv.size() != 3 && lv.size() != 6 && lv.size() != 9)
CarpetContext cc = (CarpetContext) c;
int cx, cy, cz;
int sminx, sminy, sminz;
int smaxx, smaxy, smaxz;
BlockArgument cposLocator = BlockArgument.findIn(cc, lv, 0);
BlockPos cpos = cposLocator.block.getPos();
cx = cpos.getX();
cy = cpos.getY();
cz = cpos.getZ();
if (lv.size() > cposLocator.offset)
{
throw new InternalExpressionException("Rectangular region should be specified with 3, 6, or 9 coordinates");
}
int cx;
int cy;
int cz;
int sminx;
int sminy;
int sminz;
int smaxx;
int smaxy;
int smaxz;
try
{
cx = (int)((NumericValue) lv.get(0).evalValue(c)).getLong();
cy = (int)((NumericValue) lv.get(1).evalValue(c)).getLong();
cz = (int)((NumericValue) lv.get(2).evalValue(c)).getLong();
if (lv.size()==3) // only done this way because of stupid Java lambda final reqs
Vector3Argument diffLocator = Vector3Argument.findIn(cc, lv, cposLocator.offset);
if (diffLocator.fromBlock)
{
sminx = 1;
sminy = 1;
sminz = 1;
smaxx = 1;
smaxy = 1;
smaxz = 1;
sminx = MathHelper.floor(abs(diffLocator.vec.x - cx));
sminy = MathHelper.floor(abs(diffLocator.vec.y - cx));
sminz = MathHelper.floor(abs(diffLocator.vec.z - cx));
}
else if (lv.size()==6)
else
{
sminx = MathHelper.floor(abs(diffLocator.vec.x));
sminy = MathHelper.floor(abs(diffLocator.vec.y));
sminz = MathHelper.floor(abs(diffLocator.vec.z));
}
if (lv.size() > diffLocator.offset)
{
Vector3Argument posDiff = Vector3Argument.findIn(cc, lv, diffLocator.offset);
if (posDiff.fromBlock)
{
smaxx = MathHelper.floor(abs(posDiff.vec.x - cx));
smaxy = MathHelper.floor(abs(posDiff.vec.y - cx));
smaxz = MathHelper.floor(abs(posDiff.vec.z - cx));
}
else
{
smaxx = MathHelper.floor(abs(posDiff.vec.x));
smaxy = MathHelper.floor(abs(posDiff.vec.y));
smaxz = MathHelper.floor(abs(posDiff.vec.z));
}
}
else
{
sminx = (int) ((NumericValue) lv.get(3).evalValue(c)).getLong();
sminy = (int) ((NumericValue) lv.get(4).evalValue(c)).getLong();
sminz = (int) ((NumericValue) lv.get(5).evalValue(c)).getLong();
smaxx = sminx;
smaxy = sminy;
smaxz = sminz;
}
else // size == 9
{
sminx = (int) ((NumericValue) lv.get(3).evalValue(c)).getLong();
sminy = (int) ((NumericValue) lv.get(4).evalValue(c)).getLong();
sminz = (int) ((NumericValue) lv.get(5).evalValue(c)).getLong();
smaxx = (int)((NumericValue) lv.get(6).evalValue(c)).getLong();
smaxy = (int)((NumericValue) lv.get(7).evalValue(c)).getLong();
smaxz = (int)((NumericValue) lv.get(8).evalValue(c)).getLong();
}
}
catch (ClassCastException exc)
else
{
throw new InternalExpressionException("Attempted to pass a non-number to rect");
sminx = 1;
sminy = 1;
sminz = 1;
smaxx = 1;
smaxy = 1;
smaxz = 1;
}
CarpetContext cc = (CarpetContext)c;
return (c_, t_) -> new LazyListValue()
{
final int minx = cx-sminx;
@@ -2240,6 +2428,7 @@ public class CarpetExpression
final int maxx = cx+smaxx;
final int maxy = cy+smaxy;
final int maxz = cz+smaxz;
int x;
int y;
int z;
@@ -2299,10 +2488,9 @@ public class CarpetExpression
this.expr.addLazyFunction("diamond", -1, (c, t, lv)->
{
CarpetContext cc = (CarpetContext)c;
if (lv.size() != 3 && lv.size() != 4 && lv.size() != 5)
{
throw new InternalExpressionException("'diamond' region should be specified with 3 to 5 coordinates");
}
BlockArgument cposLocator=BlockArgument.findIn((CarpetContext)c,lv,0);
BlockPos cpos = cposLocator.block.getPos();
int cx;
int cy;
@@ -2311,10 +2499,11 @@ public class CarpetExpression
int height;
try
{
cx = (int)((NumericValue) lv.get(0).evalValue(c)).getLong();
cy = (int)((NumericValue) lv.get(1).evalValue(c)).getLong();
cz = (int)((NumericValue) lv.get(2).evalValue(c)).getLong();
if (lv.size()==3)
cx = cpos.getX();
cy = cpos.getY();
cz = cpos.getZ();
if (lv.size()==cposLocator.offset)
{
Value retval = ListValue.of(
BlockValue.fromCoords(cc, cx, cy-1, cz),
@@ -2327,20 +2516,22 @@ public class CarpetExpression
);
return (_c, _t ) -> retval;
}
else if (lv.size()==4)
else if (lv.size()==1+cposLocator.offset)
{
width = (int) ((NumericValue) lv.get(3).evalValue(c)).getLong();
width = (int) ((NumericValue) lv.get(cposLocator.offset).evalValue(c)).getLong();
height = 0;
}
else // size == 5
else if(lv.size()==2+cposLocator.offset)
{
width = (int) ((NumericValue) lv.get(3).evalValue(c)).getLong();
height = (int) ((NumericValue) lv.get(4).evalValue(c)).getLong();
width = (int) ((NumericValue) lv.get(cposLocator.offset).evalValue(c)).getLong();
height = (int) ((NumericValue) lv.get(cposLocator.offset+1).evalValue(c)).getLong();
} else{
throw new InternalExpressionException("Incorrect number of arguments for 'diamond'");
}
}
catch (ClassCastException exc)
{
throw new InternalExpressionException("Attempted to pass a non-number to diamond");
throw new InternalExpressionException("Attempted to pass a non-number to 'diamond'");
}
if (height == 0)
{
@@ -2480,7 +2671,7 @@ public class CarpetExpression
public static String recognizeResource(Value value)
{
String origfile = value.getString();
String file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9/]", "");
String file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9\\-+_/]", "");
file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/"));
if (file.isEmpty())
{
@@ -2756,12 +2947,7 @@ public class CarpetExpression
});
this.expr.addLazyFunction("nbt", 1, (c, t, lv) -> {
Value v = lv.get(0).evalValue(c);
if (v instanceof NBTSerializableValue)
return (cc, tt) -> v;
Value ret = NBTSerializableValue.parseString(v.getString());
if (ret == null)
return LazyValue.NULL;
Value ret = NBTSerializableValue.fromValue(lv.get(0).evalValue(c));
return (cc, tt) -> ret;
});
@@ -2772,11 +2958,50 @@ public class CarpetExpression
return (cc, tt) -> ret;
});
this.expr.addLazyFunction("parse_nbt", 1, (c, t, lv) -> {
Value v = lv.get(0).evalValue(c);
if (v instanceof NBTSerializableValue)
{
Value parsed = ((NBTSerializableValue) v).toValue();
return (cc, tt) -> parsed;
}
NBTSerializableValue ret = NBTSerializableValue.parseString(v.getString());
if (ret == null)
return LazyValue.NULL;
Value parsed = ret.toValue();
return (cc, tt) -> parsed;
});
this.expr.addLazyFunction("encode_nbt", -1, (c, t, lv) -> {
int argSize = lv.size();
if (argSize==0 || argSize > 2) throw new InternalExpressionException("'encode_nbt' requires 1 or 2 parameters");
Value v = lv.get(0).evalValue(c);
boolean force = (argSize > 1) && lv.get(1).evalValue(c).getBoolean();
Tag tag;
try
{
tag = v.toTag(force);
}
catch (NBTSerializableValue.IncompatibleTypeException ignored)
{
throw new InternalExpressionException("cannot reliably encode to a tag the value of '"+ignored.val.getPrettyString()+"'");
}
Value tagValue = new NBTSerializableValue(tag);
return (cc, tt) -> tagValue;
});
//"overridden" native call that prints to stderr
this.expr.addLazyFunction("print", 1, (c, t, lv) ->
this.expr.addLazyFunction("print", -1, (c, t, lv) ->
{
if (lv.size() == 0 || lv.size() > 2) throw new InternalExpressionException("'print' takes one or two arguments");
ServerCommandSource s = ((CarpetContext)c).s;
Value res = lv.get(0).evalValue(c);
if (lv.size() == 2)
{
ServerPlayerEntity player = EntityValue.getPlayerByValue(s.getMinecraftServer(), res);
s = player.getCommandSource();
res = lv.get(1).evalValue(c);
}
if (res instanceof FormattedTextValue)
{
s.sendFeedback(((FormattedTextValue) res).getText(), false);
@@ -2792,7 +3017,8 @@ public class CarpetExpression
Messenger.m(s, "w " + res.getString());
}
}
return (_c, _t) -> res; // pass through for variables
Value finalRes = res;
return (_c, _t) -> finalRes; // pass through for variables
});
this.expr.addLazyFunction("format", -1, (c, t, lv) -> {
@@ -2862,9 +3088,14 @@ public class CarpetExpression
BlockPos target = ((CarpetContext)c).origin;
Vec3d posf = new Vec3d((double)target.getX()+0.5D,(double)target.getY(),(double)target.getZ()+0.5D);
ServerCommandSource s = ((CarpetContext)c).s;
Value retval = new NumericValue(s.getMinecraftServer().getCommandManager().execute(
s.withPosition(posf).withSilent().withLevel(CarpetSettings.runPermissionLevel), lv.get(0).evalValue(c).getString()));
return (c_, t_) -> retval;
try
{
Value retval = new NumericValue(s.getMinecraftServer().getCommandManager().execute(
s.withPosition(posf).withSilent().withLevel(CarpetSettings.runPermissionLevel), lv.get(0).evalValue(c).getString()));
return (c_, t_) -> retval;
}
catch (Exception ignored) {}
return LazyValue.NULL;
});
this.expr.addLazyFunction("save", 0, (c, t, lv) -> {
@@ -2945,7 +3176,7 @@ public class CarpetExpression
this.expr.addLazyFunction("seed", -1, (c, t, lv) -> {
ServerCommandSource s = ((CarpetContext)c).s;
Value ret = new NumericValue(s.getWorld().getSeed());
Value ret = new StringValue(Long.toString(s.getWorld().getSeed()));
return (cc, tt) -> ret;
});
@@ -3013,10 +3244,12 @@ public class CarpetExpression
default:
throw new InternalExpressionException("Incorrect dimension string: "+dimString);
}
}
((CarpetContext) c).s = innerSource;
Value retval = lv.get(1).evalValue(c);
((CarpetContext) c).s = outerSource;
};
if (innerSource.getWorld() == outerSource.getWorld()) return lv.get(1);
Context newCtx = c.recreate();
((CarpetContext) newCtx).s = innerSource;
newCtx.variables = c.variables;
Value retval = lv.get(1).evalValue(newCtx);
return (cc, tt) -> retval;
});
+2 -1
View File
@@ -18,8 +18,9 @@ public class Context
public static final int SIGNATURE = 7;
public static final int LOCALIZATION = 8;
public static final int LVALUE = 9;
public static final int MAPDEF = 10;
public final Map<String, LazyValue> variables = new HashMap<>();
public Map<String, LazyValue> variables = new HashMap<>();
public final ScriptHost host;
+78 -18
View File
@@ -43,7 +43,9 @@ import org.apache.commons.lang3.text.WordUtils;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.IllegalFormatException;
import java.util.Iterator;
@@ -490,6 +492,11 @@ public class Expression
//assigns const procedure to the lhs, returning its previous value
addLazyBinaryOperatorWithDelegation("->", precedence.get("def->"), false, (c, type, e, t, lv1, lv2) ->
{
if (type == Context.MAPDEF)
{
Value result = ListValue.of(lv1.evalValue(c), lv2.evalValue(c));
return (cc, tt) -> result;
}
Value v1 = lv1.evalValue(c, Context.SIGNATURE);
if (!(v1 instanceof FunctionSignatureValue))
throw new InternalExpressionException("'->' operator requires a function signature on the LHS");
@@ -1333,11 +1340,18 @@ public class Expression
return LazyListValue.range(from, to, step);
});
addFunction("m", lv ->
addLazyFunction("m", -1, (c, t, llv) ->
{
List<Value> lv = new ArrayList<>();
for (LazyValue lazyParam : llv) {
lv.add(lazyParam.evalValue(c, Context.MAPDEF)); // none type default by design
}
Value ret;
if (lv.size() == 1 && lv.get(0) instanceof LazyListValue)
return new MapValue(((LazyListValue) lv.get(0)).unroll());
return new MapValue(lv);
ret = new MapValue(((LazyListValue) lv.get(0)).unroll());
else
ret = new MapValue(lv);
return (cc, tt) -> ret;
});
addUnaryFunction("keys", v -> {
@@ -1449,20 +1463,6 @@ public class Expression
return (cc, tt) -> ret;
});
//Deprecated, use "get" instead, or . operator
addBinaryFunction("element", (v1, v2) ->
{
if (!(v1 instanceof ListValue))
throw new InternalExpressionException("First argument of 'get' should be a list");
List<Value> items = ((ListValue)v1).getItems();
long index = NumericValue.asNumber(v2).getLong();
int numitems = items.size();
long range = abs(index)/numitems;
index += (range+2)*numitems;
index = index % numitems;
return items.get((int)index);
});
addLazyFunction("put", -1, (c, t, lv) ->
{
if(lv.size()<2)
@@ -1790,6 +1790,66 @@ public class Expression
return (cc, tt) -> time;
});
addLazyFunction("unix_time", 0, (c, t, lv) ->
{
Value time = new NumericValue(System.currentTimeMillis());
return (cc, tt) -> time;
});
addFunction("convert_date", lv ->
{
int argsize = lv.size();
if (lv.size() == 0) throw new InternalExpressionException("'convert_date' requires at least one parameter");
Value value = lv.get(0);
if (argsize == 1 && !(value instanceof ListValue))
{
Calendar cal = new GregorianCalendar(Locale.ROOT);
cal.setTimeInMillis(NumericValue.asNumber(value, "timestamp").getLong());
int weekday = cal.get(Calendar.DAY_OF_WEEK)-1;
if (weekday == 0) weekday = 7;
Value retVal = ListValue.ofNums(
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH)+1,
cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
cal.get(Calendar.SECOND),
weekday,
cal.get(Calendar.DAY_OF_YEAR),
cal.get(Calendar.WEEK_OF_YEAR)
);
return retVal;
}
else if(value instanceof ListValue)
{
lv = ((ListValue) value).getItems();
argsize = lv.size();
}
Calendar cal = new GregorianCalendar(0, 0, 0, 0, 0, 0);
if (argsize == 3)
{
cal.set(
NumericValue.asNumber(lv.get(0)).getInt(),
NumericValue.asNumber(lv.get(1)).getInt()-1,
NumericValue.asNumber(lv.get(2)).getInt()
);
}
else if (argsize == 6)
{
cal.set(
NumericValue.asNumber(lv.get(0)).getInt(),
NumericValue.asNumber(lv.get(1)).getInt()-1,
NumericValue.asNumber(lv.get(2)).getInt(),
NumericValue.asNumber(lv.get(3)).getInt(),
NumericValue.asNumber(lv.get(4)).getInt(),
NumericValue.asNumber(lv.get(5)).getInt()
);
}
else throw new InternalExpressionException("Date conversion requires 3 arguments for Dates or 6 arguments, for time");
return new NumericValue(cal.getTimeInMillis());
});
addLazyFunction("profile_expr", 1, (c, t, lv) ->
{
LazyValue lazy = lv.get(0);
@@ -2000,7 +2060,7 @@ public class Expression
Tokenizer tokenizer = new Tokenizer(c, this, expression, allowComments, allowNewlineSubstitutions);
// stripping lousy but acceptable semicolons
List<Tokenizer.Token> cleanedTokens = tokenizer.fixSemicolons();
List<Tokenizer.Token> cleanedTokens = tokenizer.postProcess();
Tokenizer.Token lastFunction = null;
Tokenizer.Token previousToken = null;
+50 -6
View File
@@ -43,7 +43,7 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
this.newLinesMarkers = allowNewLineMakers;
}
public List<Token> fixSemicolons()
public List<Token> postProcess()
{
Iterable<Token> iterable = () -> this;
List<Token> originalTokens = StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
@@ -52,6 +52,9 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
while (originalTokens.size() > 0)
{
Token current = originalTokens.remove(originalTokens.size()-1);
if (current.type == Token.TokenType.MARKER && current.surface.startsWith("//"))
continue;
// skipping comments
if (!isSemicolon(current)
|| (last != null && last.type != Token.TokenType.CLOSE_PAREN && last.type != Token.TokenType.COMMA && !isSemicolon(last)))
{
@@ -60,9 +63,27 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
current.surface = ";";
current.type = Token.TokenType.OPERATOR;
}
if (current.type == Token.TokenType.MARKER)
{
// dealing with tokens in reversed order
if ("{".equals(current.surface))
{
cleanedTokens.add(current.morphedInto(Token.TokenType.OPEN_PAREN, "("));
current.morph(Token.TokenType.FUNCTION, "m");
}
else if ("[".equals(current.surface))
{
cleanedTokens.add(current.morphedInto(Token.TokenType.OPEN_PAREN, "("));
current.morph(Token.TokenType.FUNCTION, "l");
}
else if ("}".equals(current.surface) || "]".equals(current.surface))
{
current.morph(Token.TokenType.CLOSE_PAREN, ")");
}
}
cleanedTokens.add(current);
}
if (current.type != Token.TokenType.MARKER)
if (!(current.type == Token.TokenType.MARKER && current.surface.equals("$")))
last = current;
}
Collections.reverse(cleanedTokens);
@@ -242,7 +263,8 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
}
token.type = ch == '(' ? Token.TokenType.FUNCTION : Token.TokenType.VARIABLE;
}
else if (ch == '(' || ch == ')' || ch == ',')
else if (ch == '(' || ch == ')' || ch == ',' ||
ch == '{' || ch == '}' || ch == '[' || ch == ']')
{
if (ch == '(')
{
@@ -252,17 +274,21 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
{
token.type = Token.TokenType.CLOSE_PAREN;
}
else
else if (ch == ',')
{
token.type = Token.TokenType.COMMA;
}
else
{
token.type = Token.TokenType.MARKER;
}
token.append(ch);
pos++;
linepos++;
if (expression != null && context != null && previousToken != null &&
previousToken.type == Token.TokenType.OPERATOR &&
(ch == ')' || ch == ',') &&
(ch == ')' || ch == ',' || ch == ']' || ch == '}') &&
!previousToken.surface.equalsIgnoreCase(";")
)
throw new ExpressionException(context, this.expression, previousToken,
@@ -326,7 +352,9 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
}
if (previousToken == null || previousToken.type == Token.TokenType.OPERATOR
|| previousToken.type == Token.TokenType.OPEN_PAREN || previousToken.type == Token.TokenType.COMMA)
|| previousToken.type == Token.TokenType.OPEN_PAREN || previousToken.type == Token.TokenType.COMMA
|| (previousToken.type == Token.TokenType.MARKER && ( previousToken.surface.equals("{") || previousToken.surface.equals("[") ) )
)
{
token.surface += "u";
token.type = Token.TokenType.UNARY_OPERATOR;
@@ -376,6 +404,22 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
public int pos;
public int linepos;
public int lineno;
public Token morphedInto(TokenType newType, String newSurface)
{
Token created = new Token();
created.surface = newSurface;
created.type = newType;
created.pos = pos;
created.linepos = linepos;
created.lineno= lineno;
return created;
}
public void morph(TokenType type, String s)
{
this.type = type;
this.surface = s;
}
public void append(char c)
{
@@ -39,16 +39,13 @@ public class ShapesRenderer
{
this.client = minecraftClient;
shapes = new HashMap<>();
shapes.put(DimensionType.OVERWORLD, new Long2ObjectOpenHashMap<>());
shapes.put(DimensionType.THE_NETHER, new Long2ObjectOpenHashMap<>());
shapes.put(DimensionType.THE_END, new Long2ObjectOpenHashMap<>());
}
public void render(Camera camera, float partialTick)
{
IWorld iWorld = this.client.world;
DimensionType dimensionType = iWorld.getDimension().getType();
if (shapes.get(dimensionType).isEmpty()) return;
if (shapes.get(dimensionType) == null || shapes.get(dimensionType).isEmpty()) return;
long currentTime = client.world.getTime();
RenderSystem.disableTexture();
RenderSystem.enableDepthTest();
@@ -59,8 +56,7 @@ public class ShapesRenderer
//RenderSystem.shadeModel(7425);
RenderSystem.shadeModel(GL11.GL_FLAT);
RenderSystem.enableAlphaTest();
RenderSystem.defaultAlphaFunc();
//RenderSystem.alphaFunc(GL11.GL_GREATER, 0.005F);
RenderSystem.alphaFunc(GL11.GL_GREATER, 0.003f);
RenderSystem.disableCull();
RenderSystem.disableLighting();
RenderSystem.depthMask(false);
@@ -131,7 +127,7 @@ public class ShapesRenderer
long key = rshape.key();
synchronized (shapes)
{
RenderedShape<?> existing = shapes.get(dim).get(key);
RenderedShape<?> existing = shapes.computeIfAbsent(dim, d -> new Long2ObjectOpenHashMap<>()).get(key);
if (existing != null)
{ // promoting previous shape
existing.expiryTick = rshape.expiryTick;
@@ -12,7 +12,10 @@ import net.minecraft.block.Blocks;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.state.property.Property;
import net.minecraft.util.GlobalPos;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
@@ -24,8 +27,10 @@ import net.minecraft.world.World;
import net.minecraft.world.chunk.WorldChunk;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
@@ -180,6 +185,33 @@ public class BlockValue extends Value
public ServerWorld getWorld() { return world;}
@Override
public Tag toTag(boolean force)
{
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
// follows falling block convertion
CompoundTag tag = new CompoundTag();
CompoundTag state = new CompoundTag();
BlockState s = getBlockState();
state.put("Name", StringTag.of(Registry.BLOCK.getId(s.getBlock()).toString()));
Collection<Property<?>> properties = s.getProperties();
if (!properties.isEmpty())
{
CompoundTag props = new CompoundTag();
for (Property<?> p: properties)
{
props.put(p.getName(), StringTag.of(s.get(p).toString().toLowerCase(Locale.ROOT)));
}
state.put("Properties", props);
}
tag.put("BlockState", state);
CompoundTag dataTag = getData();
if (dataTag != null)
{
tag.put("TileEntityData", dataTag);
}
return tag;
}
public enum SpecificDirection {
UP("up",0.5, 0.0, 0.5, Direction.UP),
@@ -1,6 +1,5 @@
package carpet.script.value;
import carpet.CarpetSettings;
import carpet.fakes.EntityInterface;
import carpet.fakes.ItemEntityInterface;
import carpet.fakes.LivingEntityInterface;
@@ -12,10 +11,10 @@ import carpet.script.CarpetContext;
import carpet.script.EntityEventsGroup;
import carpet.script.argument.Vector3Argument;
import carpet.script.exception.InternalExpressionException;
import carpet.utils.Messenger;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.entity.player.HungerManager;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.packet.s2c.play.EntityPassengersSetS2CPacket;
import net.minecraft.network.packet.s2c.play.EntityPositionS2CPacket;
import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket;
@@ -61,6 +60,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Predicate;
@@ -87,11 +87,11 @@ public class EntityValue extends Value
EntitySelector entitySelector = selectorCache.get(selector);
if (entitySelector != null)
{
return entitySelector.getEntities(source);
return entitySelector.getEntities(source.withMaxLevel(4));
}
entitySelector = new EntitySelectorReader(new StringReader(selector), true).read();
selectorCache.put(selector, entitySelector);
return entitySelector.getEntities(source);
return entitySelector.getEntities(source.withMaxLevel(4));
}
catch (CommandSyntaxException e)
{
@@ -289,6 +289,10 @@ public class EntityValue extends Value
put("sneaking", (e, a) -> e.isSneaking()?Value.TRUE:Value.FALSE);
put("sprinting", (e, a) -> e.isSprinting()?Value.TRUE:Value.FALSE);
put("swimming", (e, a) -> e.isSwimming()?Value.TRUE:Value.FALSE);
put("persistence", (e, a) -> {
if (e instanceof MobEntity) return new NumericValue(((MobEntity) e).isPersistent());
return Value.NULL;
});
put("hunger", (e, a) -> {
if(e instanceof PlayerEntity) return new NumericValue(((PlayerEntity) e).getHungerManager().getFoodLevel());
return Value.NULL;
@@ -520,6 +524,10 @@ public class EntityValue extends Value
{
throw new InternalExpressionException("'modify' for '"+what+"' expects a value");
}
catch (IndexOutOfBoundsException ind)
{
throw new InternalExpressionException("Wrong number of arguments for `modify` option: "+what);
}
}
private static void updatePosition(Entity e, double x, double y, double z, float yaw, float pitch)
@@ -715,9 +723,23 @@ public class EntityValue extends Value
e.setCustomName(null);
return;
}
e.setCustomNameVisible(true);
boolean showName = false;
if (v instanceof ListValue)
{
showName = ((ListValue) v).getItems().get(1).getBoolean();
v = ((ListValue) v).getItems().get(0);
}
e.setCustomNameVisible(showName);
e.setCustomName(new LiteralText(v.getString()));
});
put("persistence", (e, v) ->
{
if (!(e instanceof MobEntity)) return;
if (v == null) v = Value.TRUE;
((MobEntityInterface)e).setPersistence(v.getBoolean());
});
put("dismount", (e, v) -> e.stopRiding() );
put("mount", (e, v) -> {
if (v instanceof EntityValue)
@@ -976,22 +998,37 @@ public class EntityValue extends Value
if(e instanceof PlayerEntity) ((PlayerEntity) e).getHungerManager().setSaturationLevelClient((float)NumericValue.asNumber(v).getLong());
});
// gamemode [check]
// spectate [check]
// "fire" [check]
// "extinguish" [set fire ticks to 0]
// "silent" [check]
// "gravity" [check]
// "invulnerable" [check]
put("nbt", (e, v) -> {
if (!(e instanceof PlayerEntity))
{
UUID uUID = e.getUuid();
Value tagValue = NBTSerializableValue.fromValue(v);
if (tagValue instanceof NBTSerializableValue)
{
e.fromTag(((NBTSerializableValue) tagValue).getCompoundTag());
e.setUuid(uUID);
}
}
});
put("nbt_merge", (e, v) -> {
if (!(e instanceof PlayerEntity))
{
UUID uUID = e.getUuid();
Value tagValue = NBTSerializableValue.fromValue(v);
if (tagValue instanceof NBTSerializableValue)
{
CompoundTag nbttagcompound = e.toTag((new CompoundTag()));
nbttagcompound.copyFrom(((NBTSerializableValue) tagValue).getCompoundTag());
e.fromTag(nbttagcompound);
e.setUuid(uUID);
}
}
});
// "dimension" []
// "item" []
// "count", []
// "age", [check]
// "effect_"name []
// "hold" [inventory_set?]
// "hold_offhand" [inventory_set?]
// "jump" [check]
// "nbt" <-big one, for now use run('data merge entity ...
}};
public void setEvent(CarpetContext cc, String eventName, FunctionValue fun, List<Value> args)
@@ -1001,4 +1038,14 @@ public class EntityValue extends Value
throw new InternalExpressionException("Unknown entity event: " + eventName);
((EntityInterface)entity).getEventContainer().addEvent(event, cc, fun, args);
}
@Override
public Tag toTag(boolean force)
{
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
CompoundTag tag = new CompoundTag();
tag.put("Data", getEntity().toTag( new CompoundTag()));
tag.put("Name", StringTag.of(Registry.ENTITY_TYPE.getId(entity.getType()).toString()));
return tag;
}
}
@@ -1,6 +1,9 @@
package carpet.script.value;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.text.BaseText;
import net.minecraft.text.Text;
public class FormattedTextValue extends StringValue
{
@@ -37,4 +40,11 @@ public class FormattedTextValue extends StringValue
{
return text;
}
@Override
public Tag toTag(boolean force)
{
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
return StringTag.of(Text.Serializer.toJson(text));
}
}
@@ -1,5 +1,7 @@
package carpet.script.value;
import net.minecraft.nbt.Tag;
public abstract class FrameworkValue extends Value
{
@Override
@@ -25,4 +27,10 @@ public abstract class FrameworkValue extends Value
{
throw new UnsupportedOperationException("Scarpet language component cannot be used as map key");
}
@Override
public Tag toTag(boolean force)
{
throw new UnsupportedOperationException("Scarpet language component cannot be serialized to the tag");
}
}
@@ -13,6 +13,8 @@ import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ReturnStatement;
import carpet.script.exception.ThrowStatement;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import java.util.ArrayList;
import java.util.Collections;
@@ -94,6 +96,8 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
return name.hashCode()+(int)variant;
}
@Override
public boolean equals(Object o)
{
@@ -231,4 +235,11 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
{
return args;
}
@Override
public Tag toTag(boolean force)
{
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
return StringTag.of(getString());
}
}
@@ -1,6 +1,7 @@
package carpet.script.value;
import carpet.script.exception.InternalExpressionException;
import net.minecraft.nbt.Tag;
public class GlobalValue extends Value
{
@@ -28,4 +29,10 @@ public class GlobalValue extends Value
{
throw new UnsupportedOperationException("Global value cannot be used as a map key");
}
@Override
public Tag toTag(boolean force)
{
throw new UnsupportedOperationException("Global value cannot be serialized to the tag");
}
}
@@ -1,6 +1,8 @@
package carpet.script.value;
import carpet.script.exception.InternalExpressionException;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import java.util.ArrayList;
import java.util.Iterator;
@@ -152,4 +154,11 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
{
return ("i"+getString()).hashCode();
}
@Override
public Tag toTag(boolean force)
{
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
return StringTag.of(getString());
}
}
@@ -3,13 +3,23 @@ package carpet.script.value;
import carpet.script.LazyValue;
import carpet.script.exception.InternalExpressionException;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.AbstractNumberTag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.DoubleTag;
import net.minecraft.nbt.IntTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.LongTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.util.registry.Registry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@@ -98,6 +108,13 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
{
return ListValue.wrap(Arrays.asList(list));
}
public static ListValue ofNums(Number ... list)
{
List<Value> valList = new ArrayList<>();
for (Number i : list)
valList.add(new NumericValue(i.doubleValue()));
return ListValue.wrap(valList);
}
public static LazyValue lazyEmpty()
{
@@ -447,4 +464,65 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
{
return items.hashCode();
}
private enum TagTypeCompat
{
INT,
LONG,
DBL,
LIST,
MAP,
STRING;
private static TagTypeCompat getType(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;
return STRING;
}
}
@Override
public Tag toTag(boolean force)
{
int argSize = items.size();
if (argSize == 0) return new ListTag();
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<>();
items.forEach(v -> tags.add(v.toTag(force)));
Set<TagTypeCompat> cases = EnumSet.noneOf(TagTypeCompat.class);
tags.forEach(t -> cases.add(TagTypeCompat.getType(t)));
if (cases.size()==1) // well, one type of items
{
tag.addAll(tags);
return tag;
}
if (cases.contains(TagTypeCompat.LIST)
|| cases.contains(TagTypeCompat.MAP)
|| cases.contains(TagTypeCompat.STRING)) // incompatible types
{
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
tags.forEach(t -> tag.add(StringTag.of(t.asString())));
return tag;
}
// only numbers / mixed types
if (cases.contains(TagTypeCompat.DBL))
{
tags.forEach(t -> tag.add(DoubleTag.of(((AbstractNumberTag)t).getDouble())));
}
else
{
tags.forEach(t -> tag.add(LongTag.of(((AbstractNumberTag)t).getLong())));
}
return tag;
}
}
@@ -1,6 +1,8 @@
package carpet.script.value;
import carpet.script.exception.InternalExpressionException;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import java.util.ArrayList;
import java.util.HashMap;
@@ -226,4 +228,16 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
{
return map.hashCode();
}
@Override
public Tag toTag(boolean force)
{
CompoundTag tag = new CompoundTag() ;
map.forEach( (k, v) ->
{
if (!force && !(k instanceof StringValue)) throw new NBTSerializableValue.IncompatibleTypeException(k);
tag.put(k.getString(), v.toTag(force));
});
return tag;
}
}
@@ -33,6 +33,7 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -48,6 +49,7 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
private String nbtString = null;
private Tag nbtTag = null;
private Supplier<Tag> nbtSupplier = null;
private boolean owned = false;
private NBTSerializableValue() {}
@@ -64,11 +66,18 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
throw new InternalExpressionException("Incorrect NBT data: "+nbtString);
}
};
owned = true;
}
public NBTSerializableValue(Tag tag)
{
nbtTag = tag;
owned = true;
}
public NBTSerializableValue(Supplier<Tag> tagSupplier)
{
nbtSupplier = tagSupplier;
}
public static Value fromStack(ItemStack stack)
@@ -100,7 +109,7 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
}
catch (CommandSyntaxException e)
{
return null;
throw new InternalExpressionException("Incorrect NBT tag: nbtString");
}
NBTSerializableValue value = new NBTSerializableValue(tag);
value.nbtString = nbtString;
@@ -115,6 +124,7 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
NBTSerializableValue copy = new NBTSerializableValue(nbtTag);
copy.nbtSupplier = this.nbtSupplier;
copy.nbtString = this.nbtString;
copy.owned = this.owned;
return copy;
}
@@ -122,9 +132,8 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
public Value deepcopy()
{
NBTSerializableValue copy = (NBTSerializableValue) clone();
// same fields except when tag is set - need to copy it.
if (copy.nbtTag != null)
copy.nbtTag = copy.getTag().copy();
copy.owned = false;
ensureOwnership();
return copy;
}
@@ -290,7 +299,50 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
private static Value decodeTag(Tag t)
{
if (t instanceof CompoundTag)
return new NBTSerializableValue(t);
return new NBTSerializableValue(() -> t);
if (t instanceof AbstractNumberTag)
return new NumericValue(((AbstractNumberTag) t).getDouble());
// more can be done here
return new StringValue(t.asString());
}
public Value toValue()
{
return decodeTagDeep(this.getTag());
}
public static Value fromValue(Value v)
{
if (v instanceof NBTSerializableValue)
return v;
if (v instanceof NullValue)
return Value.NULL;
return NBTSerializableValue.parseString(v.getString());
}
private static Value decodeTagDeep(Tag t)
{
if (t instanceof CompoundTag)
{
Map<Value, Value> pairs = new HashMap<>();
CompoundTag ctag = (CompoundTag)t;
for (String key: ctag.getKeys())
{
pairs.put(new StringValue(key), decodeTagDeep(ctag.get(key)));
}
return MapValue.wrap(pairs);
}
if (t instanceof AbstractListTag)
{
List<Value> elems = new ArrayList<>();
AbstractListTag<? extends Tag> ltag = (AbstractListTag<? extends Tag>)t;
for (Tag elem: ltag)
{
elems.add(decodeTagDeep(elem));
}
return ListValue.wrap(elems);
}
if (t instanceof AbstractNumberTag)
return new NumericValue(((AbstractNumberTag) t).getDouble());
// more can be done here
@@ -304,13 +356,6 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
return nbtTag;
}
private void replaceTag(Tag newTag)
{
nbtTag = newTag;
nbtString = null;
nbtSupplier = null; // just to be sure
}
@Override
public boolean equals(final Object o)
{
@@ -346,6 +391,7 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
{
try
{
ensureOwnership();
return (CompoundTag) getTag();
}
catch (ClassCastException e)
@@ -364,12 +410,12 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
public boolean put(Value where, Value value, Value conditions)
{
/// WIP
ensureOwnership();
NbtPathArgumentType.NbtPath path = cachePath(where.getString());
Tag tagToInsert = value instanceof NBTSerializableValue ?
((NBTSerializableValue) value).getTag() :
new NBTSerializableValue(value.getString()).getTag();
Tag modifiedTag;
boolean modifiedTag;
if (conditions instanceof NumericValue)
{
modifiedTag = modify_insert((int)((NumericValue) conditions).getLong(), path, tagToInsert);
@@ -390,22 +436,17 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
return false;
}
}
if (modifiedTag != null)
{
replaceTag(modifiedTag);
return true;
}
return false;
return modifiedTag;
}
private Tag modify_insert(int index, NbtPathArgumentType.NbtPath nbtPath, Tag newElement)
private boolean modify_insert(int index, NbtPathArgumentType.NbtPath nbtPath, Tag newElement)
{
return modify_insert(index, nbtPath, newElement, this.getTag().copy());
return modify_insert(index, nbtPath, newElement, this.getTag());
}
private Tag modify_insert(int index, NbtPathArgumentType.NbtPath nbtPath, Tag newElement, Tag currentTag)
private boolean modify_insert(int index, NbtPathArgumentType.NbtPath nbtPath, Tag newElement, Tag currentTag)
{
Collection<Tag> targets;
try
@@ -414,7 +455,7 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
}
catch (CommandSyntaxException e)
{
return null;
return false;
}
boolean modified = false;
@@ -428,27 +469,27 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
{
AbstractListTag<?> targetList = (AbstractListTag) target;
if (!targetList.addTag(index < 0 ? targetList.size() + index + 1 : index, newElement.copy()))
return null;
return false;
modified = true;
}
catch (IndexOutOfBoundsException ignored)
{
}
}
return modified?currentTag:null;
return modified;
}
private Tag modify_merge(NbtPathArgumentType.NbtPath nbtPath, Tag replacement) //nbtPathArgumentType$NbtPath_1, list_1)
private boolean modify_merge(NbtPathArgumentType.NbtPath nbtPath, Tag replacement) //nbtPathArgumentType$NbtPath_1, list_1)
{
if (!(replacement instanceof CompoundTag))
{
return getTag();
return false;
}
Tag originalTag = getTag().copy();
Tag ownTag = getTag();
try
{
for (Tag target : nbtPath.getOrInit(originalTag, CompoundTag::new))
for (Tag target : nbtPath.getOrInit(ownTag, CompoundTag::new))
{
if (!(target instanceof CompoundTag))
{
@@ -457,23 +498,26 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
((CompoundTag) target).copyFrom((CompoundTag) replacement);
}
}
catch (CommandSyntaxException ignored) { }
return originalTag;
catch (CommandSyntaxException ignored)
{
return false;
}
return true;
}
private Tag modify_replace(NbtPathArgumentType.NbtPath nbtPath, Tag replacement) //nbtPathArgumentType$NbtPath_1, list_1)
private boolean modify_replace(NbtPathArgumentType.NbtPath nbtPath, Tag replacement) //nbtPathArgumentType$NbtPath_1, list_1)
{
Tag originalTag = getTag().copy();
Tag tag = getTag();
String pathText = nbtPath.toString();
if (pathText.endsWith("]")) // workaround for array replacement or item in the array replacement
{
if (nbtPath.remove(originalTag)==0)
return null;
if (nbtPath.remove(tag)==0)
return false;
Pattern pattern = Pattern.compile("\\[[^\\[]*]$");
Matcher matcher = pattern.matcher(pathText);
if (!matcher.find()) // malformed path
{
return null;
return false;
}
String arrAccess = matcher.group();
int pos;
@@ -487,21 +531,21 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
}
catch (NumberFormatException e)
{
return null;
return false;
}
}
NbtPathArgumentType.NbtPath newPath = cachePath(pathText.substring(0, pathText.length()-arrAccess.length()));
return modify_insert(pos,newPath,replacement, originalTag);
return modify_insert(pos,newPath,replacement, tag);
}
try
{
nbtPath.put(originalTag, () -> replacement);
nbtPath.put(tag, () -> replacement);
}
catch (CommandSyntaxException e)
{
return null;
return false;
}
return originalTag;
return true;
}
@Override
@@ -527,13 +571,23 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
return cachePath(where.getString()).count(getTag()) > 0;
}
private void ensureOwnership()
{
if (!owned)
{
nbtTag = getTag().copy();
nbtString = null;
nbtSupplier = null; // just to be sure
owned = true;
}
}
@Override
public boolean delete(Value where)
{
NbtPathArgumentType.NbtPath path = cachePath(where.getString());
Tag tag = getTag().copy();
int removed = path.remove(tag);
if (removed > 0) replaceTag(tag);
ensureOwnership();
int removed = path.remove(getTag());
return removed > 0;
}
@@ -584,4 +638,23 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
{
return "nbt";
}
@Override
public Tag toTag(boolean force)
{
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
ensureOwnership();
return getTag();
}
public static class IncompatibleTypeException extends RuntimeException
{
private IncompatibleTypeException() {}
public Value val;
public IncompatibleTypeException(Value val)
{
this.val = val;
}
};
}
@@ -1,5 +1,8 @@
package carpet.script.value;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
public class NullValue extends NumericValue // TODO check nonsingleton code
{
@Override
@@ -50,4 +53,11 @@ public class NullValue extends NumericValue // TODO check nonsingleton code
{
return 0;
}
@Override
public Tag toTag(boolean force)
{
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
return StringTag.of("null");
}
}
@@ -1,6 +1,10 @@
package carpet.script.value;
import carpet.script.exception.InternalExpressionException;
import net.minecraft.nbt.DoubleTag;
import net.minecraft.nbt.IntTag;
import net.minecraft.nbt.LongTag;
import net.minecraft.nbt.Tag;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
@@ -204,4 +208,20 @@ public class NumericValue extends Value
{
return (int)getLong();
}
@Override
public Tag toTag(boolean force)
{
long longValue = getLong();
if (value == (double)longValue)
{
if (abs(value) < Integer.MAX_VALUE-2)
return IntTag.of((int)longValue);
return LongTag.of(getLong());
}
else
{
return DoubleTag.of(value);
}
}
}
@@ -1,5 +1,8 @@
package carpet.script.value;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
public class StringValue extends Value
{
private String str;
@@ -30,4 +33,10 @@ public class StringValue extends Value
{
return "string";
}
@Override
public Tag toTag(boolean force)
{
return StringTag.of(str);
}
}
@@ -6,6 +6,7 @@ import carpet.script.LazyValue;
import carpet.script.Tokenizer;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
import net.minecraft.nbt.Tag;
import java.util.HashMap;
import java.util.List;
@@ -144,4 +145,10 @@ public class ThreadValue extends Value
locks.clear();
}
@Override
public Tag toTag(boolean force)
{
if (!force) throw new NBTSerializableValue.IncompatibleTypeException(this);
return getValue().toTag(true);
}
}
@@ -1,6 +1,7 @@
package carpet.script.value;
import carpet.script.exception.InternalExpressionException;
import net.minecraft.nbt.Tag;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -203,4 +204,6 @@ public abstract class Value implements Comparable<Value>, Cloneable
throw new InternalExpressionException("Cannot make a copy of value: "+this);
}
}
public abstract Tag toTag(boolean force);
}