From 037321ccfd6f3306180dcd87f0b30827bcd28f21 Mon Sep 17 00:00:00 2001 From: gnembon Date: Mon, 24 Jun 2019 09:15:54 -0300 Subject: [PATCH 01/19] inventories --- .../java/carpet/script/CarpetExpression.java | 124 ++++++++++++++++-- src/main/java/carpet/script/Expression.java | 16 +++ .../java/carpet/script/value/EntityValue.java | 61 +++++---- .../java/carpet/script/value/ListValue.java | 16 +++ .../script/value/NBTSerializableValue.java | 123 +++++++++++++++++ 5 files changed, 304 insertions(+), 36 deletions(-) create mode 100644 src/main/java/carpet/script/value/NBTSerializableValue.java diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 088fed23..38600480 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -1,6 +1,7 @@ package carpet.script; import carpet.CarpetServer; +import carpet.script.value.NBTSerializableValue; import carpet.script.value.NullValue; import carpet.settings.CarpetSettings; import carpet.helpers.FeatureGenerator; @@ -26,7 +27,12 @@ import net.minecraft.block.entity.BlockEntity; import net.minecraft.enchantment.Enchantments; import net.minecraft.entity.EntityType; import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.brain.task.LookTargetUtil; import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.entity.passive.AbstractTraderEntity; +import net.minecraft.entity.passive.VillagerEntity; import net.minecraft.item.Items; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.command.arguments.ParticleArgumentType; @@ -556,7 +562,7 @@ public class CarpetExpression if (e == null) throw new InternalExpressionException("Null entity"); Value retval = ListValue.of(new NumericValue(e.x), new NumericValue(e.y), new NumericValue(e.z)); - return(c_, t_) -> retval; + return (c_, t_) -> retval; } else { @@ -607,7 +613,8 @@ public class CarpetExpression genericStateTest(c, "blast_resistance", lv, (s, p, w) -> new NumericValue(s.getBlock().getBlastResistance()))); - this.expr.addLazyFunction("top", -1, (c, t, lv) -> { + this.expr.addLazyFunction("top", -1, (c, t, lv) -> + { String type = lv.get(0).evalValue(c).getString().toLowerCase(Locale.ROOT); Heightmap.Type htype; switch (type) @@ -718,8 +725,8 @@ public class CarpetExpression return (c_, t_) -> retval; }); - this.expr.addLazyFunction("destroy", -1, (c, t, lv) -> { - + this.expr.addLazyFunction("destroy", -1, (c, t, lv) -> + { CarpetContext cc = (CarpetContext)c; ServerWorld world = cc.s.getWorld(); BlockValue.LocatorResult locator = BlockValue.fromParams(cc, lv, 0); @@ -756,8 +763,8 @@ public class CarpetExpression return (c_, t_) -> Value.TRUE; }); - this.expr.addLazyFunction("harvest", -1, (c, t, lv) -> { - + this.expr.addLazyFunction("harvest", -1, (c, t, lv) -> + { CarpetContext cc = (CarpetContext)c; World world = cc.s.getWorld(); Value entityValue = lv.get(0).evalValue(cc); @@ -776,7 +783,7 @@ public class CarpetExpression ItemStack itemstack2 = player.getMainHandStack(); itemstack2.postMine(player.world, state, where, player); ItemStack itemstack1 = itemstack2.isEmpty() ? ItemStack.EMPTY : itemstack2.copy(); - state.getBlock().afterBreak(world, player, where,state, be, itemstack1); + state.getBlock().afterBreak(world, player, where, state, be, itemstack1); world.playLevelEvent(null, 2001, where, Block.getRawIdFromState(state)); return (c_, t_) -> Value.TRUE; }); @@ -789,11 +796,11 @@ public class CarpetExpression stateStringQuery(c, "block_sound", lv, (s, p) -> BlockInfo.soundName.get(s.getSoundGroup()))); - this.expr.addLazyFunction("material",-1, (c, t, lv) -> + this.expr.addLazyFunction("material", -1, (c, t, lv) -> stateStringQuery(c, "material", lv, (s, p) -> BlockInfo.materialName.get(s.getMaterial()))); - this.expr.addLazyFunction("map_colour", -1, (c, t, lv) -> + this.expr.addLazyFunction("map_colour", -1, (c, t, lv) -> stateStringQuery(c, "map_colour", lv, (s, p) -> BlockInfo.mapColourName.get(s.getTopMaterialColor(((CarpetContext)c).s.getWorld(), p)))); @@ -807,8 +814,104 @@ public class CarpetExpression if (property == null) return LazyValue.NULL; Value retval = new StringValue(state.get(property).toString()); - return (_c, _t ) -> retval; + return (_c, _t) -> retval; }); + + } + + public void API_InventoryManipulation() + { + //inventory_get(, ) -> item_triple + this.expr.addLazyFunction("inventory_get", -1, (c, t, lv) -> { + //long stime = System.nanoTime(); + CarpetContext cc = (CarpetContext) c; + NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); + if (lv.size() == inventoryLocator.offset) + { + List fullInventory = new ArrayList<>(); + for (int i = 0, maxi = inventoryLocator.inventory.getInvSize(); i < maxi; i++) + { + fullInventory.add(ListValue.fromItemStack(inventoryLocator.inventory.getInvStack(i))); + } + Value res = ListValue.wrap(fullInventory); + //long etime = System.nanoTime(); + //CarpetSettings.LOG.error("took "+(etime-stime)/1000); + return (_c, _t) -> res; + } + int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); + if (slot < 0 || slot > inventoryLocator.inventory.getInvSize()) + throw new InternalExpressionException("Inventory has "+inventoryLocator.inventory.getInvSize()+" slots available"); + Value res = ListValue.fromItemStack(inventoryLocator.inventory.getInvStack(slot)); + //long etime = System.nanoTime(); + //CarpetSettings.LOG.error("took "+(etime-stime)/1000); + return (_c, _t) -> res; + }); + + //inventory_drop(, , ) -> entity_item (and sets slot) or null if cannot + this.expr.addLazyFunction("inventory_drop", -1, (c, t, lv) -> { + //long stime = System.nanoTime(); + CarpetContext cc = (CarpetContext) c; + NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); + if (lv.size() == inventoryLocator.offset) + throw new InternalExpressionException("slot number is required for inventory_drop"); + int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); + if (slot < 0 || slot > inventoryLocator.inventory.getInvSize()) + throw new InternalExpressionException("Inventory has "+inventoryLocator.inventory.getInvSize()+" slots available"); + int amount = 0; + if (lv.size() > inventoryLocator.offset+1) + amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); + if (amount < 0) + throw new InternalExpressionException("Cannot throw negative number of items"); + ItemStack stack = inventoryLocator.inventory.getInvStack(slot); + if (stack == null || stack.isEmpty()) + return (_c, _t) -> Value.ZERO; + if (amount == 0) + amount = stack.getCount(); + ItemStack droppedStack = inventoryLocator.inventory.takeInvStack(slot, amount); + if (droppedStack.isEmpty()) + { + return (_c, _t) -> Value.ZERO; + } + Object owner = inventoryLocator.owner; + ItemEntity item; + if (owner instanceof PlayerEntity) + item = ((PlayerEntity) owner).dropItem(droppedStack, false, true); + else if (owner instanceof LivingEntity) + { + LivingEntity villager = (LivingEntity)owner; + // stolen from LookTargetUtil.give((VillagerEntity)owner, droppedStack, (LivingEntity) owner); + double double_1 = villager.y - 0.30000001192092896D + (double)villager.getStandingEyeHeight(); + item = new ItemEntity(villager.world, villager.x, double_1, villager.z, droppedStack); + Vec3d vec3d_1 = villager.getRotationVec(1.0F).normalize().multiply(0.3);// new Vec3d(0, 0.3, 0); + item.setVelocity(vec3d_1); + item.setToDefaultPickupDelay(); + } + else + { + Vec3d point = new Vec3d(inventoryLocator.position); + item = new ItemEntity(cc.s.getWorld(), point.x+0.5, point.y+0.5, point.z+0.5, droppedStack); + item.setToDefaultPickupDelay(); + } + inventoryLocator.inventory.markDirty(); + cc.s.getWorld().spawnEntity(item); + Value res = new NumericValue(item.getStack().getCount()); + return (_c, _t) -> res; + }); + + //inventory_find(, or null (first empty slot), ) -> or null + //inventory_set(, , , ) + //inventory_remove(, , ) -> bool + + + + /* + if (slot > -1) + { + if (slot >= inv.getInvSize()) + throw new InternalExpressionException("Inventory of "+e+" has "+inv.getInvSize()+" slots only"); + itemstack = inv.getInvStack(slot); + } + */ } /** @@ -2051,6 +2154,7 @@ public class CarpetExpression API_BlockManipulation(); API_EntityManipulation(); + API_InventoryManipulation(); API_IteratingOverAreasOfBlocks(); API_AuxiliaryAspects(); } diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 9515d8bb..51ea5072 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -19,6 +19,7 @@ import carpet.script.value.ListValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; import carpet.script.value.Value; +import carpet.settings.CarpetSettings; import java.math.BigInteger; import java.util.ArrayList; @@ -1833,6 +1834,21 @@ public class Expression implements Cloneable return LazyListValue.range(from, to, step); }); + addBinaryFunction("get", (v1, v2) -> { + if (v1 instanceof LazyListValue || !(v1 instanceof ListValue)) + { + throw new InternalExpressionException("First argument of element should be a list"); + } + List 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); + }); + + //Deprecated addBinaryFunction("element", (v1, v2) -> { if (v1 instanceof LazyListValue || !(v1 instanceof ListValue)) { diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java index 9117b02e..f51c0598 100644 --- a/src/main/java/carpet/script/value/EntityValue.java +++ b/src/main/java/carpet/script/value/EntityValue.java @@ -4,35 +4,33 @@ import carpet.fakes.MobEntityInterface; import carpet.script.exception.InternalExpressionException; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.client.network.packet.EntityVelocityUpdateS2CPacket; +import net.minecraft.command.EntitySelector; +import net.minecraft.command.EntitySelectorReader; +import net.minecraft.command.arguments.NbtPathArgumentType; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityPose; import net.minecraft.entity.EntityType; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.goal.GoToWalkTargetGoal; +import net.minecraft.entity.ai.goal.Goal; import net.minecraft.entity.effect.StatusEffect; import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.nbt.Tag; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.command.EntitySelector; -import net.minecraft.command.EntitySelectorReader; -import net.minecraft.command.arguments.NbtPathArgumentType; -import net.minecraft.entity.mob.MobEntityWithAi; // EntityCreature; -import net.minecraft.entity.mob.MobEntity; //LivingEntity; -import net.minecraft.entity.ai.goal.Goal; -import net.minecraft.entity.ai.goal.GoToWalkTargetGoal; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.mob.MobEntityWithAi; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundTag; -import net.minecraft.client.network.packet.EntityVelocityUpdateS2CPacket; -import net.minecraft.potion.Potion; +import net.minecraft.nbt.Tag; import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.LiteralText; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; -import net.minecraft.text.LiteralText; import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; @@ -64,7 +62,7 @@ public class EntityValue extends Value { return entitySelector.getEntities(source); } - entitySelector = new EntitySelectorReader(new StringReader(selector), true).build(); + entitySelector = new EntitySelectorReader(new StringReader(selector), true).read(); selectorCache.put(selector, entitySelector); return entitySelector.getEntities(source); } @@ -104,6 +102,21 @@ public class EntityValue extends Value @Override public Value in(Value v) { + if (v instanceof ListValue) + { + List values = ((ListValue) v).getItems(); + String what = values.get(0).getString(); + Value arg = null; + if (values.size() == 2) + { + arg = values.get(1); + } + else if (values.size() > 2) + { + arg = ListValue.wrap(values.subList(1,values.size())); + } + return this.get(what, arg); + } String what = v.getString(); return this.get(what, null); } @@ -139,6 +152,7 @@ public class EntityValue extends Value put("feet", EquipmentSlot.FEET); }}; private static Map> featureAccessors = new HashMap>() {{ + //put("test", (e, a) -> a == null ? Value.NULL : new StringValue(a.getString())); put("removed", (entity, arg) -> new NumericValue(entity.removed)); put("uuid",(e, a) -> new StringValue(e.getUuidAsString())); put("id",(e, a) -> new NumericValue(e.getEntityId())); @@ -273,19 +287,14 @@ public class EntityValue extends Value if (where == null) throw new InternalExpressionException("Unknown inventory slot: "+a.getString()); if (e instanceof LivingEntity) - { - ItemStack itemstack = ((LivingEntity)e).getEquippedStack(where); - if (!itemstack.isEmpty()) - { - return ListValue.of( - new StringValue(Registry.ITEM.getId(itemstack.getItem()).getPath()), - new NumericValue(itemstack.getCount()), - new StringValue(itemstack.toTag(new CompoundTag()).toString()) - ); - } - } + return ListValue.fromItemStack(((LivingEntity)e).getEquippedStack(where)); return Value.NULL; + }); + put("selected_slot", (e, a) -> { + if (e instanceof PlayerEntity) + return new NumericValue(((PlayerEntity) e).inventory.selectedSlot); + return null; }); put("nbt",(e, a) -> { diff --git a/src/main/java/carpet/script/value/ListValue.java b/src/main/java/carpet/script/value/ListValue.java index e8cfe02f..a8b20d72 100644 --- a/src/main/java/carpet/script/value/ListValue.java +++ b/src/main/java/carpet/script/value/ListValue.java @@ -1,6 +1,9 @@ package carpet.script.value; import carpet.script.exception.InternalExpressionException; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.registry.Registry; import java.util.ArrayList; import java.util.Arrays; @@ -44,6 +47,19 @@ public class ListValue extends Value items = new ArrayList<>(); items.addAll(list); } + + public static Value fromItemStack(ItemStack itemstack) + { + if (itemstack == null || itemstack.isEmpty()) + return Value.NULL; + return ListValue.of( + new StringValue(Registry.ITEM.getId(itemstack.getItem()).getPath()), + new NumericValue(itemstack.getCount()), + new NBTSerializableValue(itemstack) + ); + } + + public static ListValue wrap(List list) { ListValue created = new ListValue(); diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java new file mode 100644 index 00000000..1feac122 --- /dev/null +++ b/src/main/java/carpet/script/value/NBTSerializableValue.java @@ -0,0 +1,123 @@ +package carpet.script.value; + +import carpet.script.CarpetContext; +import carpet.script.LazyValue; +import carpet.script.exception.InternalExpressionException; +import net.minecraft.block.entity.HopperBlockEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.passive.AbstractTraderEntity; +import net.minecraft.entity.passive.VillagerEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.math.BlockPos; + +import java.util.List; +import java.util.function.Supplier; + +public class NBTSerializableValue extends Value +{ + private Object what; + private String nbtString = null; + private CompoundTag nbtTag = null; + private Supplier nbtSupplier; + + public NBTSerializableValue(ItemStack stack) + { + what = stack; + nbtSupplier = () -> ((ItemStack)what).toTag(new CompoundTag()); + } + + public static InventoryLocator locateInventory(CarpetContext c, List params, int offset) + { + try + { + Inventory inv = null; + Value v1 = params.get(0 + offset).evalValue(c); + if (v1 instanceof EntityValue) + { + Entity e = ((EntityValue) v1).getEntity(); + if (e instanceof PlayerEntity) inv = ((PlayerEntity) e).inventory; + else if (e instanceof Inventory) inv = (Inventory)e; + else if (e instanceof VillagerEntity) inv = ((VillagerEntity) e).getInventory(); + + if (inv == null) + throw new InternalExpressionException("Entity "+e+" has no inventory"); + + return new InventoryLocator(e, e.getBlockPos(), inv, offset+1); + } + else if (v1 instanceof BlockValue) + { + BlockPos pos = ((BlockValue) v1).getPos(); + if (pos == null) + throw new InternalExpressionException("Block to acess inventory needs to be positioned in the world"); + inv = HopperBlockEntity.getInventoryAt(c.s.getWorld(), pos); + if (inv == null) + throw new InternalExpressionException("Block at "+pos+" has no inventory"); + return new InventoryLocator(pos, pos, inv, offset+1); + } + else if (v1 instanceof ListValue) + { + List args = ((ListValue) v1).getItems(); + BlockPos pos = new BlockPos( + NumericValue.asNumber(args.get(0)).getDouble(), + NumericValue.asNumber(args.get(1)).getDouble(), + NumericValue.asNumber(args.get(2)).getDouble()); + inv = HopperBlockEntity.getInventoryAt(c.s.getWorld(), pos); + if (inv == null) + throw new InternalExpressionException("Block at "+pos+" has no inventory"); + return new InventoryLocator(pos, pos, inv, offset+1); + } + BlockPos pos = new BlockPos( + NumericValue.asNumber(v1).getDouble(), + NumericValue.asNumber(params.get(1 + offset).evalValue(c)).getDouble(), + NumericValue.asNumber(params.get(2 + offset).evalValue(c)).getDouble()); + inv = HopperBlockEntity.getInventoryAt(c.s.getWorld(), pos); + if (inv == null) + throw new InternalExpressionException("Block at "+pos+" has no inventory"); + return new InventoryLocator(pos, pos, inv, offset+3); + } + catch (IndexOutOfBoundsException e) + { + throw new InternalExpressionException("Inventory should be defined either by three coordinates, a block value, or an entity"); + } + } + + private CompoundTag getTag() + { + if (nbtTag == null) + nbtTag = nbtSupplier.get(); + return nbtTag; + } + + + @Override + public String getString() + { + if (nbtString == null) + nbtString = getTag().toString(); + return nbtString; + } + + @Override + public boolean getBoolean() + { + return true; + } + + public static class InventoryLocator + { + public Object owner; + public BlockPos position; + public Inventory inventory; + public int offset; + InventoryLocator(Object owner, BlockPos pos, Inventory i, int o) + { + this.owner = owner; + position = pos; + inventory = i; + offset = o; + } + } +} From 7534c4b0617e68207bb57a2b2b4311a33ac093aa Mon Sep 17 00:00:00 2001 From: gnembon Date: Mon, 24 Jun 2019 14:38:00 -0300 Subject: [PATCH 02/19] fill in inventory calls --- .../java/carpet/script/CarpetExpression.java | 128 ++++++++++++++++-- .../script/value/NBTSerializableValue.java | 59 ++++++-- 2 files changed, 166 insertions(+), 21 deletions(-) diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 38600480..8d8f14b2 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -19,11 +19,14 @@ import carpet.script.value.StringValue; import carpet.script.value.Value; import carpet.utils.BlockInfo; import carpet.utils.Messenger; +import com.google.common.collect.Sets; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; +import net.minecraft.command.arguments.ItemStackArgument; +import net.minecraft.command.arguments.ItemStringReader; import net.minecraft.enchantment.Enchantments; import net.minecraft.entity.EntityType; import net.minecraft.entity.EquipmentSlot; @@ -50,10 +53,7 @@ import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.text.LiteralText; import net.minecraft.util.Identifier; import net.minecraft.sound.SoundCategory; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.EulerRotation; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.*; import net.minecraft.util.registry.Registry; import net.minecraft.world.LightType; import net.minecraft.world.World; @@ -899,19 +899,125 @@ public class CarpetExpression }); //inventory_find(, or null (first empty slot), ) -> or null + this.expr.addLazyFunction("inventory_find", -1, (c, t, lv) -> { + //long stime = System.nanoTime(); + CarpetContext cc = (CarpetContext) c; + NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); + ItemStackArgument itemArg = null; + if (lv.size() > inventoryLocator.offset) + { + Value secondArg = lv.get(inventoryLocator.offset+0).evalValue(c); + if (!(secondArg instanceof NullValue)) + { + itemArg = NBTSerializableValue.parseItem(secondArg.getString()); + if (itemArg == null) + throw new InternalExpressionException("Incorrect item format: "+secondArg.getString()); + } + } + int startIndex = 0; + if (lv.size() > inventoryLocator.offset+1) + { + startIndex = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); + } + startIndex = NBTSerializableValue.validateSlot(startIndex, inventoryLocator.inventory); + for (int i = startIndex, maxi = inventoryLocator.inventory.getInvSize(); i < maxi; i++) + { + ItemStack stack = inventoryLocator.inventory.getInvStack(i); + if ( (itemArg == null && stack.isEmpty()) || (itemArg != null && itemArg.getItem().equals(stack.getItem())) ) + { + Value res = new NumericValue(i); + return (_c, _t) -> res; + } + } + //long etime = System.nanoTime(); + //CarpetSettings.LOG.error("took "+(etime-stime)/1000); + return (_c, _t) -> Value.NULL; + }); + //inventory_set(, , , ) + this.expr.addLazyFunction("inventory_set", -1, (c, t, lv) -> { + //long stime = System.nanoTime(); + CarpetContext cc = (CarpetContext) c; + NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); + + if (lv.size() <= inventoryLocator.offset+2) + throw new InternalExpressionException("inventory_set requires at least slot number and new stack size, and optional new item"); + int slot = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+0).evalValue(c)).getLong(); + slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); + int count = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); + if (count == 0) + { + // clear slot + ItemStack removedStack = inventoryLocator.inventory.removeInvStack(slot); + //Value res = ListValue.fromItemStack(removedStack); + return (_c, _t) -> ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares + } + if (lv.size() <= inventoryLocator.offset+3) + { + ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); + ItemStack newStack = previousStack.copy(); + newStack.setCount(count); + inventoryLocator.inventory.setInvStack(slot, newStack); + return (_c, _t) -> ListValue.fromItemStack(previousStack); + } + ItemStackArgument newitem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset+2).evalValue(c).getString()); + ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); + try + { + inventoryLocator.inventory.setInvStack(slot, newitem.createStack(count, false)); + } + catch (CommandSyntaxException e) + { + throw new InternalExpressionException(e.getMessage()); + } + return (_c, _t) -> ListValue.fromItemStack(previousStack); + }); + //inventory_remove(, , ) -> bool + this.expr.addLazyFunction("inventory_remove", -1, (c, t, lv) -> { + //long stime = System.nanoTime(); + CarpetContext cc = (CarpetContext) c; + NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); - - /* - if (slot > -1) + if (lv.size() <= inventoryLocator.offset+1) + throw new InternalExpressionException("inventory_set requires at least an item to be removed"); + ItemStackArgument searchItem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset).evalValue(c).getString()); + int amount = 1; + if (lv.size() > inventoryLocator.offset+2) { - if (slot >= inv.getInvSize()) - throw new InternalExpressionException("Inventory of "+e+" has "+inv.getInvSize()+" slots only"); - itemstack = inv.getInvStack(slot); + amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+2).evalValue(c)).getLong(); } - */ + // not enough + if ( (amount == 1) && (inventoryLocator.inventory.containsAnyInInv(Sets.newHashSet(searchItem.getItem()))) || + inventoryLocator.inventory.getInvAmountOf(searchItem.getItem()) >= amount ) + return (_c, _t) -> Value.FALSE; + for (int i = 0, maxi = inventoryLocator.inventory.getInvSize(); i < maxi; i++) + { + ItemStack stack = inventoryLocator.inventory.getInvStack(i); + if (stack.isEmpty()) + continue; + if (!stack.getItem().equals(searchItem.getItem())) + continue; + int left = stack.getCount()-amount; + if (left > 0) + { + stack.setCount(left); + inventoryLocator.inventory.setInvStack(i, stack); + return (_c, _t) -> Value.TRUE; + } + else + { + inventoryLocator.inventory.removeInvStack(i); + amount -= stack.getCount(); + } + } + if (amount > 0) + throw new InternalExpressionException("Something bad happened - cannot pull all items from inventory"); + return (_c, _t) -> Value.TRUE; + + }); + } /** diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java index 1feac122..8e3a0efa 100644 --- a/src/main/java/carpet/script/value/NBTSerializableValue.java +++ b/src/main/java/carpet/script/value/NBTSerializableValue.java @@ -3,7 +3,12 @@ package carpet.script.value; import carpet.script.CarpetContext; import carpet.script.LazyValue; import carpet.script.exception.InternalExpressionException; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.entity.HopperBlockEntity; +import net.minecraft.command.arguments.ItemStackArgument; +import net.minecraft.command.arguments.ItemStackArgumentType; +import net.minecraft.command.arguments.ItemStringReader; import net.minecraft.entity.Entity; import net.minecraft.entity.passive.AbstractTraderEntity; import net.minecraft.entity.passive.VillagerEntity; @@ -12,8 +17,11 @@ import net.minecraft.inventory.Inventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundTag; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Supplier; public class NBTSerializableValue extends Value @@ -26,7 +34,7 @@ public class NBTSerializableValue extends Value public NBTSerializableValue(ItemStack stack) { what = stack; - nbtSupplier = () -> ((ItemStack)what).toTag(new CompoundTag()); + nbtSupplier = () -> ((ItemStack) what).toTag(new CompoundTag()); } public static InventoryLocator locateInventory(CarpetContext c, List params, int offset) @@ -39,13 +47,13 @@ public class NBTSerializableValue extends Value { Entity e = ((EntityValue) v1).getEntity(); if (e instanceof PlayerEntity) inv = ((PlayerEntity) e).inventory; - else if (e instanceof Inventory) inv = (Inventory)e; + else if (e instanceof Inventory) inv = (Inventory) e; else if (e instanceof VillagerEntity) inv = ((VillagerEntity) e).getInventory(); if (inv == null) - throw new InternalExpressionException("Entity "+e+" has no inventory"); + throw new InternalExpressionException("Entity " + e + " has no inventory"); - return new InventoryLocator(e, e.getBlockPos(), inv, offset+1); + return new InventoryLocator(e, e.getBlockPos(), inv, offset + 1); } else if (v1 instanceof BlockValue) { @@ -54,8 +62,8 @@ public class NBTSerializableValue extends Value throw new InternalExpressionException("Block to acess inventory needs to be positioned in the world"); inv = HopperBlockEntity.getInventoryAt(c.s.getWorld(), pos); if (inv == null) - throw new InternalExpressionException("Block at "+pos+" has no inventory"); - return new InventoryLocator(pos, pos, inv, offset+1); + throw new InternalExpressionException("Block at " + pos + " has no inventory"); + return new InventoryLocator(pos, pos, inv, offset + 1); } else if (v1 instanceof ListValue) { @@ -66,8 +74,8 @@ public class NBTSerializableValue extends Value NumericValue.asNumber(args.get(2)).getDouble()); inv = HopperBlockEntity.getInventoryAt(c.s.getWorld(), pos); if (inv == null) - throw new InternalExpressionException("Block at "+pos+" has no inventory"); - return new InventoryLocator(pos, pos, inv, offset+1); + throw new InternalExpressionException("Block at " + pos + " has no inventory"); + return new InventoryLocator(pos, pos, inv, offset + 1); } BlockPos pos = new BlockPos( NumericValue.asNumber(v1).getDouble(), @@ -75,8 +83,8 @@ public class NBTSerializableValue extends Value NumericValue.asNumber(params.get(2 + offset).evalValue(c)).getDouble()); inv = HopperBlockEntity.getInventoryAt(c.s.getWorld(), pos); if (inv == null) - throw new InternalExpressionException("Block at "+pos+" has no inventory"); - return new InventoryLocator(pos, pos, inv, offset+3); + throw new InternalExpressionException("Block at " + pos + " has no inventory"); + return new InventoryLocator(pos, pos, inv, offset + 3); } catch (IndexOutOfBoundsException e) { @@ -84,6 +92,37 @@ public class NBTSerializableValue extends Value } } + private static Map itemCache = new HashMap<>(); + public static ItemStackArgument parseItem(String itemString) + { + try + { + ItemStackArgument res = itemCache.get(itemString); + if (res != null) + return res; + ItemStringReader parser = (new ItemStringReader(new StringReader(itemString), false)).consume(); + res = new ItemStackArgument(parser.getItem(), parser.getTag()); + itemCache.put(itemString, res); + if (itemCache.size()>64000) + itemCache.clear(); + return res; + } + catch (CommandSyntaxException e) + { + return null; + } + } + + public static int validateSlot(int slot, Inventory inv) + { + int invSize = inv.getInvSize(); + if (slot < 0) + slot = invSize + slot; + if (slot < 0 || slot >= invSize) + throw new InternalExpressionException("Slot for inventory should be between 0 and "+(invSize-1)); + return slot; + } + private CompoundTag getTag() { if (nbtTag == null) From ff203a0e730c77c29ddf1c23b6d1d69424bb4a8a Mon Sep 17 00:00:00 2001 From: gnembon Date: Tue, 25 Jun 2019 09:33:13 -0300 Subject: [PATCH 03/19] inventories --- .../java/carpet/script/CarpetExpression.java | 64 +++++++-- .../java/carpet/script/value/BlockValue.java | 122 ++++++++++++++++++ 2 files changed, 178 insertions(+), 8 deletions(-) diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 8d8f14b2..734ee0fa 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -36,6 +36,10 @@ import net.minecraft.entity.ai.brain.task.LookTargetUtil; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.passive.AbstractTraderEntity; import net.minecraft.entity.passive.VillagerEntity; +import net.minecraft.item.AutomaticItemPlacementContext; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemUsageContext; import net.minecraft.item.Items; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.command.arguments.ParticleArgumentType; @@ -51,6 +55,7 @@ import net.minecraft.state.property.Property; import net.minecraft.state.StateFactory; import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.text.LiteralText; +import net.minecraft.util.Hand; import net.minecraft.util.Identifier; import net.minecraft.sound.SoundCategory; import net.minecraft.util.math.*; @@ -816,6 +821,47 @@ public class CarpetExpression Value retval = new StringValue(state.get(property).toString()); return (_c, _t) -> retval; }); + this.expr.addLazyFunction("place_item", -1, (c, t, lv) -> + { + CarpetContext cc = (CarpetContext) c; + String itemString = lv.get(0).evalValue(c).getString(); + BlockValue.VectorLocator locator = BlockValue.locateVec(cc, lv, 1); + ItemStackArgument stackArg = NBTSerializableValue.parseItem(itemString); + BlockPos where = new BlockPos(locator.vec); + Direction side = Direction.UP; + if (lv.size() > locator.offset) + { + String key = lv.get(locator.offset).evalValue(c).getString(); + side = BlockValue.DIRECTION_MAP.get(key); + if (side == null) + throw new InternalExpressionException("unknown direction: " + key); + } + if (stackArg.getItem() instanceof BlockItem) + { + BlockItem blockItem = (BlockItem) stackArg.getItem(); + ItemPlacementContext ctx = null; + try + { + ctx = new AutomaticItemPlacementContext(cc.s.getWorld(),new BlockPos(locator.vec), side, stackArg.createStack(1, false), side ); + } + catch (CommandSyntaxException e) + { + throw new InternalExpressionException(e.getMessage()); + } + BlockState placementState = blockItem.getBlock().getPlacementState(ctx); + if (placementState != null) + { + if (placementState.canPlaceAt(cc.s.getWorld(), where)) + { + CarpetSettings.impendingFillSkipUpdates = !CarpetSettings.fillUpdates; + cc.s.getWorld().setBlockState(where, placementState, 2); + CarpetSettings.impendingFillSkipUpdates = false; + return (_c, _t) -> Value.TRUE; + } + } + } + return (_c, _t) -> Value.FALSE; + }); } @@ -940,7 +986,7 @@ public class CarpetExpression CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); - if (lv.size() <= inventoryLocator.offset+2) + if (lv.size() < inventoryLocator.offset+2) throw new InternalExpressionException("inventory_set requires at least slot number and new stack size, and optional new item"); int slot = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+0).evalValue(c)).getLong(); slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); @@ -952,7 +998,7 @@ public class CarpetExpression //Value res = ListValue.fromItemStack(removedStack); return (_c, _t) -> ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares } - if (lv.size() <= inventoryLocator.offset+3) + if (lv.size() < inventoryLocator.offset+3) { ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); ItemStack newStack = previousStack.copy(); @@ -980,18 +1026,20 @@ public class CarpetExpression CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); - if (lv.size() <= inventoryLocator.offset+1) + if (lv.size() <= inventoryLocator.offset) throw new InternalExpressionException("inventory_set requires at least an item to be removed"); ItemStackArgument searchItem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset).evalValue(c).getString()); int amount = 1; - if (lv.size() > inventoryLocator.offset+2) + if (lv.size() > inventoryLocator.offset+1) { - amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+2).evalValue(c)).getLong(); + amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); } // not enough - if ( (amount == 1) && (inventoryLocator.inventory.containsAnyInInv(Sets.newHashSet(searchItem.getItem()))) || - inventoryLocator.inventory.getInvAmountOf(searchItem.getItem()) >= amount ) + if (((amount == 1) && (!inventoryLocator.inventory.containsAnyInInv(Sets.newHashSet(searchItem.getItem())))) + || (inventoryLocator.inventory.countInInv(searchItem.getItem()) < amount)) + { return (_c, _t) -> Value.FALSE; + } for (int i = 0, maxi = inventoryLocator.inventory.getInvSize(); i < maxi; i++) { ItemStack stack = inventoryLocator.inventory.getInvStack(i); @@ -1017,9 +1065,9 @@ public class CarpetExpression return (_c, _t) -> Value.TRUE; }); - } + /** *

Entity API

*
diff --git a/src/main/java/carpet/script/value/BlockValue.java b/src/main/java/carpet/script/value/BlockValue.java index f113788c..045622f5 100644 --- a/src/main/java/carpet/script/value/BlockValue.java +++ b/src/main/java/carpet/script/value/BlockValue.java @@ -8,7 +8,14 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.BlockState; import net.minecraft.command.arguments.BlockArgumentParser; import net.minecraft.block.Blocks; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.AutomaticItemPlacementContext; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; import net.minecraft.world.World; @@ -19,6 +26,14 @@ import java.util.Map; public class BlockValue extends Value { + public static final Map DIRECTION_MAP = new HashMap() {{ + put("up", Direction.UP); + put("down", Direction.DOWN); + put("east", Direction.EAST); + put("west", Direction.WEST); + put("north", Direction.NORTH); + put("south", Direction.SOUTH); + }}; public static final BlockValue AIR = new BlockValue(Blocks.AIR.getDefaultState(), null, BlockPos.ORIGIN); public static final BlockValue NULL = new BlockValue(null, null, null); private BlockState blockState; @@ -239,4 +254,111 @@ public class BlockValue extends Value pitch = p; } } + + /*public enum SpecificDirection { + UP("up",0.5, 0.0, 0.5, Direction.UP), + + UPNORTH ("upnorth", 0.5, 0.0, 0.4, Direction.NORTH), + UPSOUTH ("upsouth", 0.5, 0.0, 0.6, Direction.SOUTH), + UPEAST("upeast", 0.6, 0.0, 0.5, Direction.EAST), + UPWEST("upwest", 0.4, 0.0, 0.5, Direction.WEST), + + DOWN("down", 0.5, 1.0, 0.5, Direction.DOWN), + + DOWNNORTH ("downnorth", 0.5, 0.0, 0.4, Direction.NORTH), + DOWNSOUTH ("downsouth", 0.5, 0.0, 0.6, Direction.SOUTH), + DOWNEAST("downeast", 0.6, 0.0, 0.5, Direction.EAST), + DOWNWEST("downwest", 0.4, 0.0, 0.5, Direction.WEST), + + + 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 ("northup", 0.5, 0.6, 1.0, Direction.NORTH), + SOUTHUP ("southup", 0.5, 0.6, 0.0, Direction.SOUTH), + EASTUP("eastup", 0.0, 0.6, 0.5, Direction.EAST), + WESTUP("westup", 1.0, 0.6, 0.5, Direction.WEST), + + + NORTHUP (), + SOUTHUP(), + EASTUP(), + WESTUP(); + + private static final Direction[] ALL = values(); + private static final Map NAME_MAP = (Map)Arrays.stream(ALL).collect(Collectors.toMap(Direction::getName, (direction_1) -> { + return direction_1; + })); + + private SpecificDirection(String name, double hitx, double hity, double hitz, Direction blockFacing) + { + + } + } + + public class PlacementContext extends ItemPlacementContext { + private final Direction facing; + + public static final Map DIRECTION_MAP = new HashMap() {{ + put("up", Direction.UP); + put("down", Direction.DOWN); + put("east", Direction.EAST); + put("west", Direction.WEST); + put("north", Direction.NORTH); + put("south", Direction.SOUTH); + }}; + public + + public PlacementContext(World world_1, BlockPos blockPos_1, Direction direction_1, ItemStack itemStack_1, Direction direction_2) { + super(world_1, (PlayerEntity)null, Hand.MAIN_HAND, itemStack_1, new BlockHitResult(new Vec3d((double)blockPos_1.getX() + 0.5D, (double)blockPos_1.getY(), (double)blockPos_1.getZ() + 0.5D), direction_2, blockPos_1, false)); + this.facing = direction_1; + } + + public BlockPos getBlockPos() { + return this.hit.getBlockPos(); + } + + public boolean canPlace() { + return this.world.getBlockState(this.hit.getBlockPos()).canReplace(this); + } + + public boolean canReplaceExisting() { + return this.canPlace(); + } + + public Direction getPlayerLookDirection() { + return Direction.DOWN; + } + + public Direction[] getPlacementDirections() { + 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 getPlayerFacing() { + return this.facing.getAxis() == Direction.Axis.Y ? Direction.NORTH : this.facing; + } + + public boolean isPlayerSneaking() { + return false; + } + + public float getPlayerYaw() { + return (float)(this.facing.getHorizontal() * 90); + } + }*/ } From 4b1a1d41dcfb21ae8cae9b878901559e43f0d565 Mon Sep 17 00:00:00 2001 From: gnembon Date: Tue, 25 Jun 2019 12:17:04 -0300 Subject: [PATCH 04/19] item placement --- .../java/carpet/script/CarpetExpression.java | 22 +++-- src/main/java/carpet/script/Expression.java | 8 +- .../java/carpet/script/value/BlockValue.java | 87 ++++++++++--------- 3 files changed, 61 insertions(+), 56 deletions(-) diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 734ee0fa..8dcfb2c5 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -827,27 +827,31 @@ public class CarpetExpression String itemString = lv.get(0).evalValue(c).getString(); BlockValue.VectorLocator locator = BlockValue.locateVec(cc, lv, 1); ItemStackArgument stackArg = NBTSerializableValue.parseItem(itemString); - BlockPos where = new BlockPos(locator.vec); - Direction side = Direction.UP; - if (lv.size() > locator.offset) + if (stackArg == null) { - String key = lv.get(locator.offset).evalValue(c).getString(); - side = BlockValue.DIRECTION_MAP.get(key); - if (side == null) - throw new InternalExpressionException("unknown direction: " + key); + throw new InternalExpressionException("unknown item: "+itemString); } + BlockPos where = new BlockPos(locator.vec); + String facing = "up"; + if (lv.size() > locator.offset) + facing = lv.get(locator.offset).evalValue(c).getString(); + boolean sneakPlace = false; + if (lv.size() > locator.offset+1) + sneakPlace = lv.get(locator.offset+1).evalValue(c).getBoolean(); if (stackArg.getItem() instanceof BlockItem) { BlockItem blockItem = (BlockItem) stackArg.getItem(); - ItemPlacementContext ctx = null; + BlockValue.PlacementContext ctx; try { - ctx = new AutomaticItemPlacementContext(cc.s.getWorld(),new BlockPos(locator.vec), side, stackArg.createStack(1, false), side ); + ctx = BlockValue.PlacementContext.from(cc.s.getWorld(), where, facing, sneakPlace, stackArg.createStack(1, false)); } catch (CommandSyntaxException e) { throw new InternalExpressionException(e.getMessage()); } + if (!ctx.canPlace()) + return (_c, _t) -> Value.FALSE; BlockState placementState = blockItem.getBlock().getPlacementState(ctx); if (placementState != null) { diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 51ea5072..d4f3a49c 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -2770,10 +2770,10 @@ public class Expression implements Cloneable { return exit.retval; } - catch (StackOverflowError ignored) - { - throw new ExpressionException("Your thoughts are too deep"); - } + //catch (StackOverflowError ignored) + //{ + // throw new ExpressionException("Your thoughts are too deep"); + //} catch (InternalExpressionException exc) { throw new ExpressionException("Your expression result is incorrect:"+exc.getMessage()); diff --git a/src/main/java/carpet/script/value/BlockValue.java b/src/main/java/carpet/script/value/BlockValue.java index 045622f5..718ee5fe 100644 --- a/src/main/java/carpet/script/value/BlockValue.java +++ b/src/main/java/carpet/script/value/BlockValue.java @@ -20,9 +20,11 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; import net.minecraft.world.World; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public class BlockValue extends Value { @@ -255,80 +257,79 @@ public class BlockValue extends Value } } - /*public enum SpecificDirection { + public enum SpecificDirection { UP("up",0.5, 0.0, 0.5, Direction.UP), - UPNORTH ("upnorth", 0.5, 0.0, 0.4, Direction.NORTH), - UPSOUTH ("upsouth", 0.5, 0.0, 0.6, Direction.SOUTH), - UPEAST("upeast", 0.6, 0.0, 0.5, Direction.EAST), - UPWEST("upwest", 0.4, 0.0, 0.5, Direction.WEST), + UPNORTH ("upnorth", 0.5, 0.0, 0.4, Direction.UP), + UPSOUTH ("upsouth", 0.5, 0.0, 0.6, Direction.UP), + UPEAST("upeast", 0.6, 0.0, 0.5, Direction.UP), + UPWEST("upwest", 0.4, 0.0, 0.5, Direction.UP), DOWN("down", 0.5, 1.0, 0.5, Direction.DOWN), - DOWNNORTH ("downnorth", 0.5, 0.0, 0.4, Direction.NORTH), - DOWNSOUTH ("downsouth", 0.5, 0.0, 0.6, Direction.SOUTH), - DOWNEAST("downeast", 0.6, 0.0, 0.5, Direction.EAST), - DOWNWEST("downwest", 0.4, 0.0, 0.5, Direction.WEST), + DOWNNORTH ("downnorth", 0.5, 1.0, 0.4, Direction.DOWN), + DOWNSOUTH ("downsouth", 0.5, 1.0, 0.6, Direction.DOWN), + DOWNEAST("downeast", 0.6, 1.0, 0.5, Direction.DOWN), + DOWNWEST("downwest", 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), EAST("east", 0.0, 0.4, 0.5, Direction.EAST), WEST("west", 1.0, 0.4, 0.5, Direction.WEST), + NORTHUP ("northup", 0.5, 0.6, 1.0, Direction.NORTH), SOUTHUP ("southup", 0.5, 0.6, 0.0, Direction.SOUTH), EASTUP("eastup", 0.0, 0.6, 0.5, Direction.EAST), - WESTUP("westup", 1.0, 0.6, 0.5, Direction.WEST), + WESTUP("westup", 1.0, 0.6, 0.5, Direction.WEST); + public String name; + public Vec3d hitOffset; + public Direction facing; - NORTHUP (), - SOUTHUP(), - EASTUP(), - WESTUP(); + private static final Map DIRECTION_MAP = Arrays.stream(values()).collect(Collectors.toMap(SpecificDirection::getName, d -> d)); - private static final Direction[] ALL = values(); - private static final Map NAME_MAP = (Map)Arrays.stream(ALL).collect(Collectors.toMap(Direction::getName, (direction_1) -> { - return direction_1; - })); private SpecificDirection(String name, double hitx, double hity, double hitz, Direction blockFacing) { - + this.name = name; + this.hitOffset = new Vec3d(hitx, hity, hitz); + this.facing = blockFacing; + } + private String getName() + { + return name; } } - public class PlacementContext extends ItemPlacementContext { + public static class PlacementContext extends ItemPlacementContext { private final Direction facing; + private final boolean sneakPlace; - public static final Map DIRECTION_MAP = new HashMap() {{ - put("up", Direction.UP); - put("down", Direction.DOWN); - put("east", Direction.EAST); - put("west", Direction.WEST); - put("north", Direction.NORTH); - put("south", Direction.SOUTH); - }}; - public - - public PlacementContext(World world_1, BlockPos blockPos_1, Direction direction_1, ItemStack itemStack_1, Direction direction_2) { - super(world_1, (PlayerEntity)null, Hand.MAIN_HAND, itemStack_1, new BlockHitResult(new Vec3d((double)blockPos_1.getX() + 0.5D, (double)blockPos_1.getY(), (double)blockPos_1.getZ() + 0.5D), direction_2, blockPos_1, false)); + public static PlacementContext from(World world, BlockPos pos, String direction, boolean sneakPlace, ItemStack itemStack) + { + SpecificDirection dir = SpecificDirection.DIRECTION_MAP.get(direction); + if (dir == null) + throw new InternalExpressionException("unknown block placement direction: "+direction); + BlockHitResult hitres = new BlockHitResult( + new Vec3d(pos).add(dir.hitOffset), + dir.facing, + pos, + false); + return new PlacementContext(world, pos, dir.facing, sneakPlace, itemStack, hitres); + } + public PlacementContext(World world_1, BlockPos blockPos_1, Direction direction_1, boolean sneakPlace, ItemStack itemStack_1, BlockHitResult hitres) { + super(world_1, null, Hand.MAIN_HAND, itemStack_1, hitres); this.facing = direction_1; + this.sneakPlace = sneakPlace; } public BlockPos getBlockPos() { return this.hit.getBlockPos(); } - public boolean canPlace() { - return this.world.getBlockState(this.hit.getBlockPos()).canReplace(this); - } - - public boolean canReplaceExisting() { - return this.canPlace(); - } - public Direction getPlayerLookDirection() { - return Direction.DOWN; + return facing.getOpposite(); } public Direction[] getPlacementDirections() { @@ -354,11 +355,11 @@ public class BlockValue extends Value } public boolean isPlayerSneaking() { - return false; + return sneakPlace; } public float getPlayerYaw() { return (float)(this.facing.getHorizontal() * 90); } - }*/ + } } From 2979924f245cb65a6cda390e74f67f6ca4b02a36 Mon Sep 17 00:00:00 2001 From: gnembon Date: Wed, 26 Jun 2019 01:18:01 -0300 Subject: [PATCH 05/19] inevntories finished --- .../java/carpet/script/CarpetExpression.java | 53 +++++++++---------- .../java/carpet/script/value/BlockValue.java | 30 +++++------ .../java/carpet/script/value/EntityValue.java | 11 ++++ .../java/carpet/settings/CarpetSettings.java | 8 +-- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 8dcfb2c5..a470505b 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -1,69 +1,64 @@ package carpet.script; import carpet.CarpetServer; -import carpet.script.value.NBTSerializableValue; -import carpet.script.value.NullValue; -import carpet.settings.CarpetSettings; -import carpet.helpers.FeatureGenerator; import carpet.fakes.MinecraftServerInterface; +import carpet.helpers.FeatureGenerator; +import carpet.script.Fluff.TriFunction; import carpet.script.exception.CarpetExpressionException; import carpet.script.exception.ExpressionException; import carpet.script.exception.InternalExpressionException; -import carpet.script.Fluff.TriFunction; import carpet.script.value.BlockValue; import carpet.script.value.EntityValue; import carpet.script.value.LazyListValue; import carpet.script.value.ListValue; +import carpet.script.value.NBTSerializableValue; +import carpet.script.value.NullValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; import carpet.script.value.Value; +import carpet.settings.CarpetSettings; import carpet.utils.BlockInfo; import carpet.utils.Messenger; import com.google.common.collect.Sets; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.Block; +import net.minecraft.block.BlockPlacementEnvironment; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.network.packet.PlaySoundIdS2CPacket; import net.minecraft.command.arguments.ItemStackArgument; -import net.minecraft.command.arguments.ItemStringReader; +import net.minecraft.command.arguments.ParticleArgumentType; import net.minecraft.enchantment.Enchantments; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.ai.brain.task.LookTargetUtil; import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.entity.passive.AbstractTraderEntity; -import net.minecraft.entity.passive.VillagerEntity; -import net.minecraft.item.AutomaticItemPlacementContext; -import net.minecraft.item.BlockItem; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemUsageContext; -import net.minecraft.item.Items; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.command.arguments.ParticleArgumentType; -import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; -import net.minecraft.client.network.packet.PlaySoundIdS2CPacket; +import net.minecraft.item.Items; import net.minecraft.particle.ParticleEffect; -import net.minecraft.block.BlockPlacementEnvironment; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.state.property.Property; -import net.minecraft.state.StateFactory; import net.minecraft.predicate.entity.EntityPredicates; -import net.minecraft.text.LiteralText; -import net.minecraft.util.Hand; -import net.minecraft.util.Identifier; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; -import net.minecraft.util.math.*; +import net.minecraft.state.StateFactory; +import net.minecraft.state.property.Property; +import net.minecraft.text.LiteralText; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.EulerRotation; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; +import net.minecraft.world.Heightmap; import net.minecraft.world.LightType; import net.minecraft.world.World; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.world.Heightmap; import net.minecraft.world.loot.context.LootContext; import net.minecraft.world.loot.context.LootContextParameters; import org.apache.commons.lang3.tuple.Pair; diff --git a/src/main/java/carpet/script/value/BlockValue.java b/src/main/java/carpet/script/value/BlockValue.java index 718ee5fe..31bef14e 100644 --- a/src/main/java/carpet/script/value/BlockValue.java +++ b/src/main/java/carpet/script/value/BlockValue.java @@ -8,8 +8,6 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.BlockState; import net.minecraft.command.arguments.BlockArgumentParser; import net.minecraft.block.Blocks; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.AutomaticItemPlacementContext; import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemStack; import net.minecraft.util.Hand; @@ -260,17 +258,17 @@ public class BlockValue extends Value public enum SpecificDirection { UP("up",0.5, 0.0, 0.5, Direction.UP), - UPNORTH ("upnorth", 0.5, 0.0, 0.4, Direction.UP), - UPSOUTH ("upsouth", 0.5, 0.0, 0.6, Direction.UP), - UPEAST("upeast", 0.6, 0.0, 0.5, Direction.UP), - UPWEST("upwest", 0.4, 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), + 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 ("downnorth", 0.5, 1.0, 0.4, Direction.DOWN), - DOWNSOUTH ("downsouth", 0.5, 1.0, 0.6, Direction.DOWN), - DOWNEAST("downeast", 0.6, 1.0, 0.5, Direction.DOWN), - DOWNWEST("downwest", 0.4, 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), + DOWNEAST("dow-neast", 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), @@ -278,10 +276,10 @@ public class BlockValue extends Value EAST("east", 0.0, 0.4, 0.5, Direction.EAST), WEST("west", 1.0, 0.4, 0.5, Direction.WEST), - NORTHUP ("northup", 0.5, 0.6, 1.0, Direction.NORTH), - SOUTHUP ("southup", 0.5, 0.6, 0.0, Direction.SOUTH), - EASTUP("eastup", 0.0, 0.6, 0.5, Direction.EAST), - WESTUP("westup", 1.0, 0.6, 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), + EASTUP("east-up", 0.0, 0.6, 0.5, Direction.EAST), + WESTUP("west-up", 1.0, 0.6, 0.5, Direction.WEST); public String name; public Vec3d hitOffset; @@ -290,7 +288,7 @@ public class BlockValue extends Value private static final Map DIRECTION_MAP = Arrays.stream(values()).collect(Collectors.toMap(SpecificDirection::getName, d -> d)); - private SpecificDirection(String name, double hitx, double hity, double hitz, Direction blockFacing) + SpecificDirection(String name, double hitx, double hity, double hitz, Direction blockFacing) { this.name = name; this.hitOffset = new Vec3d(hitx, hity, hitz); @@ -318,7 +316,7 @@ public class BlockValue extends Value false); return new PlacementContext(world, pos, dir.facing, sneakPlace, itemStack, hitres); } - public PlacementContext(World world_1, BlockPos blockPos_1, Direction direction_1, boolean sneakPlace, ItemStack itemStack_1, BlockHitResult hitres) { + private PlacementContext(World world_1, BlockPos blockPos_1, Direction direction_1, boolean sneakPlace, ItemStack itemStack_1, BlockHitResult hitres) { super(world_1, null, Hand.MAIN_HAND, itemStack_1, hitres); this.facing = direction_1; this.sneakPlace = sneakPlace; diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java index f51c0598..9845e712 100644 --- a/src/main/java/carpet/script/value/EntityValue.java +++ b/src/main/java/carpet/script/value/EntityValue.java @@ -29,6 +29,7 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.LiteralText; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; import org.apache.commons.lang3.tuple.Pair; @@ -297,6 +298,16 @@ public class EntityValue extends Value return null; }); + put("facing", (e, a) -> { + int index = 0; + if (a != null) + index = (6+(int)NumericValue.asNumber(a).getLong())%6; + if (index < 0 || index > 5) + throw new InternalExpressionException("facing order should be between -6 and 5"); + + return new StringValue(Direction.getEntityFacingOrder(e)[index].asString()); + }); + put("nbt",(e, a) -> { CompoundTag nbttagcompound = e.toTag((new CompoundTag())); if (a==null) diff --git a/src/main/java/carpet/settings/CarpetSettings.java b/src/main/java/carpet/settings/CarpetSettings.java index 3e2c00b7..c3bb5d95 100644 --- a/src/main/java/carpet/settings/CarpetSettings.java +++ b/src/main/java/carpet/settings/CarpetSettings.java @@ -51,11 +51,7 @@ public class CarpetSettings @Rule(desc = "Dropping entire stacks works also from on the crafting UI result slot", category = {BUGFIX, SURVIVAL}) public static boolean ctrlQCraftingFix = false; - @Rule( - desc = "Parrots don't get of your shoulders until you receive damage", - category = {SURVIVAL, FEATURE}, - validate = Validator.WIP.class - ) + @Rule(desc = "Parrots don't get of your shoulders until you receive proper damage", category = {SURVIVAL, FEATURE}) public static boolean persistentParrots = false; /*@Rule( @@ -208,7 +204,7 @@ public class CarpetSettings @Rule(desc = "Enables /script command", extra = "An in-game scripting API for Scarpet programming language", category = COMMAND) public static boolean commandScript = true; - @Rule(desc = "Enables /player command to control/spawn players", category = COMMAND, validate = Validator.WIP.class) + @Rule(desc = "Enables /player command to control/spawn players", category = COMMAND) public static boolean commandPlayer = true; @Rule(desc = "Placing carpets may issue carpet commands for non-op players", category = SURVIVAL) From df9fcfd4583de3b835658b623363fda1a77145a2 Mon Sep 17 00:00:00 2001 From: gnembon Date: Wed, 26 Jun 2019 01:32:58 -0300 Subject: [PATCH 06/19] cleanup --- .../java/carpet/script/CarpetExpression.java | 74 ++++++++----------- .../java/carpet/script/value/BlockValue.java | 18 +---- 2 files changed, 35 insertions(+), 57 deletions(-) diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index a470505b..79a98772 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -788,34 +788,6 @@ public class CarpetExpression return (c_, t_) -> Value.TRUE; }); - this.expr.addLazyFunction("blocks_movement", -1, (c, t, lv) -> - booleanStateTest(c, "blocks_movement", lv, (s, p) -> - !s.canPlaceAtSide(((CarpetContext) c).s.getWorld(), p, BlockPlacementEnvironment.LAND))); - - this.expr.addLazyFunction("block_sound", -1, (c, t, lv) -> - stateStringQuery(c, "block_sound", lv, (s, p) -> - BlockInfo.soundName.get(s.getSoundGroup()))); - - this.expr.addLazyFunction("material", -1, (c, t, lv) -> - stateStringQuery(c, "material", lv, (s, p) -> - BlockInfo.materialName.get(s.getMaterial()))); - - this.expr.addLazyFunction("map_colour", -1, (c, t, lv) -> - stateStringQuery(c, "map_colour", lv, (s, p) -> - BlockInfo.mapColourName.get(s.getTopMaterialColor(((CarpetContext)c).s.getWorld(), p)))); - - this.expr.addLazyFunction("property", -1, (c, t, lv) -> - { - BlockValue.LocatorResult locator = BlockValue.fromParams((CarpetContext) c, lv, 0); - BlockState state = locator.block.getBlockState(); - String tag = lv.get(locator.offset).evalValue(c).getString(); - StateFactory states = state.getBlock().getStateFactory(); - Property property = states.getProperty(tag); - if (property == null) - return LazyValue.NULL; - Value retval = new StringValue(state.get(property).toString()); - return (_c, _t) -> retval; - }); this.expr.addLazyFunction("place_item", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; @@ -862,13 +834,42 @@ public class CarpetExpression return (_c, _t) -> Value.FALSE; }); + this.expr.addLazyFunction("blocks_movement", -1, (c, t, lv) -> + booleanStateTest(c, "blocks_movement", lv, (s, p) -> + !s.canPlaceAtSide(((CarpetContext) c).s.getWorld(), p, BlockPlacementEnvironment.LAND))); + + this.expr.addLazyFunction("block_sound", -1, (c, t, lv) -> + stateStringQuery(c, "block_sound", lv, (s, p) -> + BlockInfo.soundName.get(s.getSoundGroup()))); + + this.expr.addLazyFunction("material", -1, (c, t, lv) -> + stateStringQuery(c, "material", lv, (s, p) -> + BlockInfo.materialName.get(s.getMaterial()))); + + this.expr.addLazyFunction("map_colour", -1, (c, t, lv) -> + stateStringQuery(c, "map_colour", lv, (s, p) -> + BlockInfo.mapColourName.get(s.getTopMaterialColor(((CarpetContext)c).s.getWorld(), p)))); + + this.expr.addLazyFunction("property", -1, (c, t, lv) -> + { + BlockValue.LocatorResult locator = BlockValue.fromParams((CarpetContext) c, lv, 0); + BlockState state = locator.block.getBlockState(); + String tag = lv.get(locator.offset).evalValue(c).getString(); + StateFactory states = state.getBlock().getStateFactory(); + Property property = states.getProperty(tag); + if (property == null) + return LazyValue.NULL; + Value retval = new StringValue(state.get(property).toString()); + return (_c, _t) -> retval; + }); + + } public void API_InventoryManipulation() { //inventory_get(, ) -> item_triple this.expr.addLazyFunction("inventory_get", -1, (c, t, lv) -> { - //long stime = System.nanoTime(); CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); if (lv.size() == inventoryLocator.offset) @@ -879,22 +880,17 @@ public class CarpetExpression fullInventory.add(ListValue.fromItemStack(inventoryLocator.inventory.getInvStack(i))); } Value res = ListValue.wrap(fullInventory); - //long etime = System.nanoTime(); - //CarpetSettings.LOG.error("took "+(etime-stime)/1000); return (_c, _t) -> res; } int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); if (slot < 0 || slot > inventoryLocator.inventory.getInvSize()) throw new InternalExpressionException("Inventory has "+inventoryLocator.inventory.getInvSize()+" slots available"); Value res = ListValue.fromItemStack(inventoryLocator.inventory.getInvStack(slot)); - //long etime = System.nanoTime(); - //CarpetSettings.LOG.error("took "+(etime-stime)/1000); return (_c, _t) -> res; }); //inventory_drop(, , ) -> entity_item (and sets slot) or null if cannot this.expr.addLazyFunction("inventory_drop", -1, (c, t, lv) -> { - //long stime = System.nanoTime(); CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); if (lv.size() == inventoryLocator.offset) @@ -945,7 +941,6 @@ public class CarpetExpression //inventory_find(, or null (first empty slot), ) -> or null this.expr.addLazyFunction("inventory_find", -1, (c, t, lv) -> { - //long stime = System.nanoTime(); CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); ItemStackArgument itemArg = null; @@ -974,14 +969,11 @@ public class CarpetExpression return (_c, _t) -> res; } } - //long etime = System.nanoTime(); - //CarpetSettings.LOG.error("took "+(etime-stime)/1000); return (_c, _t) -> Value.NULL; }); //inventory_set(, , , ) this.expr.addLazyFunction("inventory_set", -1, (c, t, lv) -> { - //long stime = System.nanoTime(); CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); @@ -994,8 +986,8 @@ public class CarpetExpression { // clear slot ItemStack removedStack = inventoryLocator.inventory.removeInvStack(slot); - //Value res = ListValue.fromItemStack(removedStack); - return (_c, _t) -> ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares + //Value res = ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares + return (_c, _t) -> ListValue.fromItemStack(removedStack); } if (lv.size() < inventoryLocator.offset+3) { @@ -1021,7 +1013,6 @@ public class CarpetExpression //inventory_remove(, , ) -> bool this.expr.addLazyFunction("inventory_remove", -1, (c, t, lv) -> { - //long stime = System.nanoTime(); CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); @@ -1062,7 +1053,6 @@ public class CarpetExpression if (amount > 0) throw new InternalExpressionException("Something bad happened - cannot pull all items from inventory"); return (_c, _t) -> Value.TRUE; - }); } diff --git a/src/main/java/carpet/script/value/BlockValue.java b/src/main/java/carpet/script/value/BlockValue.java index 31bef14e..3ba7f719 100644 --- a/src/main/java/carpet/script/value/BlockValue.java +++ b/src/main/java/carpet/script/value/BlockValue.java @@ -26,14 +26,6 @@ import java.util.stream.Collectors; public class BlockValue extends Value { - public static final Map DIRECTION_MAP = new HashMap() {{ - put("up", Direction.UP); - put("down", Direction.DOWN); - put("east", Direction.EAST); - put("west", Direction.WEST); - put("north", Direction.NORTH); - put("south", Direction.SOUTH); - }}; public static final BlockValue AIR = new BlockValue(Blocks.AIR.getDefaultState(), null, BlockPos.ORIGIN); public static final BlockValue NULL = new BlockValue(null, null, null); private BlockState blockState; @@ -309,14 +301,10 @@ public class BlockValue extends Value SpecificDirection dir = SpecificDirection.DIRECTION_MAP.get(direction); if (dir == null) throw new InternalExpressionException("unknown block placement direction: "+direction); - BlockHitResult hitres = new BlockHitResult( - new Vec3d(pos).add(dir.hitOffset), - dir.facing, - pos, - false); - return new PlacementContext(world, pos, dir.facing, sneakPlace, itemStack, hitres); + BlockHitResult hitres = new BlockHitResult(new Vec3d(pos).add(dir.hitOffset), dir.facing, pos, false); + return new PlacementContext(world, dir.facing, sneakPlace, itemStack, hitres); } - private PlacementContext(World world_1, BlockPos blockPos_1, Direction direction_1, boolean sneakPlace, ItemStack itemStack_1, BlockHitResult hitres) { + private PlacementContext(World world_1, Direction direction_1, boolean sneakPlace, ItemStack itemStack_1, BlockHitResult hitres) { super(world_1, null, Hand.MAIN_HAND, itemStack_1, hitres); this.facing = direction_1; this.sneakPlace = sneakPlace; From b5b628e8444fc7e2c0b7a637600ca44719947e2a Mon Sep 17 00:00:00 2001 From: gnembon Date: Wed, 26 Jun 2019 02:05:32 -0300 Subject: [PATCH 07/19] sounds --- src/main/java/carpet/script/CarpetExpression.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 79a98772..8f84fe7c 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -46,6 +46,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; import net.minecraft.state.StateFactory; import net.minecraft.state.property.Property; @@ -827,7 +828,10 @@ public class CarpetExpression CarpetSettings.impendingFillSkipUpdates = !CarpetSettings.fillUpdates; cc.s.getWorld().setBlockState(where, placementState, 2); CarpetSettings.impendingFillSkipUpdates = false; + BlockSoundGroup blockSoundGroup = placementState.getSoundGroup(); + cc.s.getWorld().playSound(null, where, blockSoundGroup.getPlaceSound(), SoundCategory.BLOCKS, (blockSoundGroup.getVolume() + 1.0F) / 2.0F, blockSoundGroup.getPitch() * 0.8F); return (_c, _t) -> Value.TRUE; + } } } From 0048b666b4d385d3a6762ebd3f9b746d94e3f80b Mon Sep 17 00:00:00 2001 From: gnembon Date: Thu, 27 Jun 2019 09:13:45 -0300 Subject: [PATCH 08/19] light blocking --- src/main/java/carpet/utils/BlockInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/carpet/utils/BlockInfo.java b/src/main/java/carpet/utils/BlockInfo.java index bfdda0e4..6632ee43 100644 --- a/src/main/java/carpet/utils/BlockInfo.java +++ b/src/main/java/carpet/utils/BlockInfo.java @@ -175,7 +175,7 @@ public class BlockInfo lst.add(Messenger.s(String.format(" - Brightness in: %.2f, above: %.2f", world.getBrightness(pos), world.getBrightness(pos.up())))); lst.add(Messenger.s(String.format(" - Is opaque: %s", material.isSolid() ))); //lst.add(Messenger.s(String.format(" - Light opacity: %d", state.getOpacity(world,pos)))); - //lst.add(Messenger.s(String.format(" - Blocks light: %s", state.propagatesSkylightDown(world, pos)))); + lst.add(Messenger.s(String.format(" - Blocks light: %s", state.getMaterial().blocksLight()))); //lst.add(Messenger.s(String.format(" - Emitted light: %d", state.getLightValue()))); //lst.add(Messenger.s(String.format(" - Picks neighbour light value: %s", state.useNeighborBrightness(world, pos)))); lst.add(Messenger.s("")); From ae3c5afcd633c41f058e5bd212d5aff8571209fc Mon Sep 17 00:00:00 2001 From: gnembon Date: Thu, 27 Jun 2019 10:51:38 -0300 Subject: [PATCH 09/19] publishing to local maven --- .gitignore | 1 + build.gradle | 3 +++ gradle.properties | 2 +- src/main/java/carpet/settings/CarpetSettings.java | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9563893d..2105712d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ build/ out/ classes/ +publish/ # idea diff --git a/build.gradle b/build.gradle index 68e69288..3d29089d 100644 --- a/build.gradle +++ b/build.gradle @@ -76,5 +76,8 @@ publishing { repositories { // uncomment to publish to the local maven // mavenLocal() + maven { + url "$projectDir/publish" + } } } diff --git a/gradle.properties b/gradle.properties index 5a5a3144..e73bb52d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ org.gradle.jvmargs=-Xmx1G loader_version=0.4.8+build.155 # Mod Properties - mod_version = 0.1a + mod_version = 1.0.0+v190627 maven_group = carpet archives_base_name = fabric-carpet diff --git a/src/main/java/carpet/settings/CarpetSettings.java b/src/main/java/carpet/settings/CarpetSettings.java index 3e2c00b7..4445d442 100644 --- a/src/main/java/carpet/settings/CarpetSettings.java +++ b/src/main/java/carpet/settings/CarpetSettings.java @@ -25,7 +25,7 @@ import static carpet.settings.RuleCategory.SURVIVAL; public class CarpetSettings { - public static final String carpetVersion = "v19_06_24alpha"; + public static final String carpetVersion = "v190627"; public static final Logger LOG = LogManager.getLogger(); public static boolean skipGenerationChecks = false; public static boolean impendingFillSkipUpdates = false; From 276e2d3769f06e2dd021ea8e52c6db039fd7864b Mon Sep 17 00:00:00 2001 From: gnembon Date: Thu, 27 Jun 2019 16:27:38 -0300 Subject: [PATCH 10/19] extensions --- build.gradle | 2 +- src/main/java/carpet/settings/Rule.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 3d29089d..0852c2e2 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 archivesBaseName = project.archives_base_name -version = project.mod_version +version = project.minecraft_version+'-'+project.mod_version group = project.maven_group minecraft { diff --git a/src/main/java/carpet/settings/Rule.java b/src/main/java/carpet/settings/Rule.java index b4c5b316..99876938 100644 --- a/src/main/java/carpet/settings/Rule.java +++ b/src/main/java/carpet/settings/Rule.java @@ -17,7 +17,7 @@ import java.lang.annotation.Target; */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) -@interface Rule +public @interface Rule { /** * The rule name, by default the same as the field name From 022f84b4693f71a8879f48b5e722429499386e79 Mon Sep 17 00:00:00 2001 From: gnembon Date: Fri, 28 Jun 2019 23:30:25 -0300 Subject: [PATCH 11/19] lazy rule fetching --- .../java/carpet/commands/CarpetCommand.java | 53 +++++++++++-------- .../java/carpet/settings/SettingsManager.java | 2 +- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/main/java/carpet/commands/CarpetCommand.java b/src/main/java/carpet/commands/CarpetCommand.java index ab64394a..cbea2e8f 100644 --- a/src/main/java/carpet/commands/CarpetCommand.java +++ b/src/main/java/carpet/commands/CarpetCommand.java @@ -8,7 +8,9 @@ import carpet.utils.Messenger; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.text.BaseText; @@ -23,6 +25,14 @@ import static net.minecraft.server.command.CommandSource.suggestMatching; public class CarpetCommand { + private static ParsedRule getRule(CommandContext ctx) throws CommandSyntaxException + { + String ruleName = StringArgumentType.getString(ctx, "rule"); + ParsedRule rule = SettingsManager.getRule(ruleName); + if (rule == null) + throw new SimpleCommandExceptionType(Messenger.c("rb Unknown rule: "+ruleName)).create(); + return rule; + } public static void register(CommandDispatcher dispatcher) { LiteralArgumentBuilder literalargumentbuilder = literal("carpet").requires((player) -> @@ -41,30 +51,27 @@ public class CarpetCommand suggests( (c, b)->suggestMatching(SettingsManager.getCategories(), b)). executes( (c) -> listSettings(c.getSource(), String.format("CarpetMod Settings matching \"%s\"", StringArgumentType.getString(c, "tag")), - CarpetServer.settingsManager.getRulesMatching(StringArgumentType.getString(c, "tag")))))); + CarpetServer.settingsManager.getRulesMatching(StringArgumentType.getString(c, "tag")))))). + then(literal("removeDefault"). + requires(s -> !CarpetServer.settingsManager.locked). + then(argument("rule", StringArgumentType.word()). + suggests( (c, b) -> suggestMatching(SettingsManager.getRules().stream().map(r -> r.name), b)). + executes((c) -> removeDefault(c.getSource(), getRule(c))))). + then(literal("setDefault"). + requires(s -> !CarpetServer.settingsManager.locked). + then(argument("rule", StringArgumentType.word()). + suggests( (c, b) -> suggestMatching(SettingsManager.getRules().stream().map(r -> r.name), b)). + then(argument("value", StringArgumentType.word()). + suggests((c, b)-> suggestMatching(getRule(c).options, b)). + executes((c) -> setDefault(c.getSource(), getRule(c), StringArgumentType.getString(c, "value")))))). + then(argument("rule", StringArgumentType.word()). + suggests( (c, b) -> suggestMatching(SettingsManager.getRules().stream().map(r -> r.name), b)). + requires(s -> !CarpetServer.settingsManager.locked ). + executes( (c) -> displayRuleMenu(c.getSource(),getRule(c))). + then(argument("value", StringArgumentType.word()). + suggests((c, b)-> suggestMatching(getRule(c).options,b)). + executes((c) -> setRule(c.getSource(), getRule(c), StringArgumentType.getString(c, "value"))))); - for (ParsedRule rule: SettingsManager.getRules()) - { - literalargumentbuilder.then(literal(rule.name).executes( (context) -> - displayRuleMenu(context.getSource(),rule))); - literalargumentbuilder.then(literal("removeDefault"). - requires(s -> !CarpetServer.settingsManager.locked). - then(literal(rule.name).executes((context) -> - removeDefault(context.getSource(), rule)))); - literalargumentbuilder.then(literal(rule.name). - requires(s -> !CarpetServer.settingsManager.locked). - then(argument("value", StringArgumentType.word()). - suggests((c, b)-> suggestMatching(rule.options,b)). - executes((context) -> - setRule(context.getSource(), rule, StringArgumentType.getString(context, "value"))))); - literalargumentbuilder.then(literal("setDefault"). - requires(s -> !CarpetServer.settingsManager.locked). - then(literal(rule.name). - then(argument("value", StringArgumentType.word()). - suggests((c, b)-> suggestMatching(rule.options,b)). - executes((context) -> - setDefault(context.getSource(), rule, StringArgumentType.getString(context, "value")))))); - } dispatcher.register(literalargumentbuilder); } diff --git a/src/main/java/carpet/settings/SettingsManager.java b/src/main/java/carpet/settings/SettingsManager.java index 601e74a2..9152ff83 100644 --- a/src/main/java/carpet/settings/SettingsManager.java +++ b/src/main/java/carpet/settings/SettingsManager.java @@ -71,7 +71,7 @@ public class SettingsManager } - public ParsedRule getRule(String name) + public static ParsedRule getRule(String name) { return rules.get(name); } From 3964145907eb44684518779bc6cc481102e5a7aa Mon Sep 17 00:00:00 2001 From: gnembon Date: Fri, 28 Jun 2019 22:20:43 -0300 Subject: [PATCH 12/19] Settings refactor - adding source to observers --- src/main/java/carpet/settings/ParsedRule.java | 2 +- src/main/java/carpet/settings/SettingsManager.java | 10 +++++----- src/main/resources/fabric.mod.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/carpet/settings/ParsedRule.java b/src/main/java/carpet/settings/ParsedRule.java index b0f0073e..13f02aa5 100644 --- a/src/main/java/carpet/settings/ParsedRule.java +++ b/src/main/java/carpet/settings/ParsedRule.java @@ -117,7 +117,7 @@ public final class ParsedRule implements Comparable { if (!value.equals(get())) { this.field.set(null, value); - SettingsManager.notifyRuleChanged(this, stringValue); + SettingsManager.notifyRuleChanged(source, this, stringValue); } } catch (IllegalAccessException e) diff --git a/src/main/java/carpet/settings/SettingsManager.java b/src/main/java/carpet/settings/SettingsManager.java index 9152ff83..5d0cd0b2 100644 --- a/src/main/java/carpet/settings/SettingsManager.java +++ b/src/main/java/carpet/settings/SettingsManager.java @@ -7,6 +7,7 @@ import net.minecraft.server.network.ServerPlayerEntity; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.util.TriConsumer; import java.io.BufferedReader; import java.io.File; @@ -25,7 +26,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeMap; -import java.util.function.BiConsumer; import java.util.stream.Collectors; public class SettingsManager @@ -34,7 +34,7 @@ public class SettingsManager private static Map> rules = new HashMap<>(); public boolean locked; private MinecraftServer server; - private static List, String>> observers = new ArrayList<>(); + private static List, String>> observers = new ArrayList<>(); public SettingsManager(MinecraftServer server) { @@ -53,14 +53,14 @@ public class SettingsManager } } - public static void addRuleObserver(BiConsumer, String> observer) + public static void addRuleObserver(TriConsumer, String> observer) { observers.add(observer); } - static void notifyRuleChanged(ParsedRule rule, String userTypedValue) + static void notifyRuleChanged(ServerCommandSource source, ParsedRule rule, String userTypedValue) { - observers.forEach(observer -> observer.accept(rule, userTypedValue)); + observers.forEach(observer -> observer.accept(source, rule, userTypedValue)); } public static Iterable getCategories() diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 8e65cc90..9673bf12 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "id": "carpet", - "version": "0.1", + "version": "${version}", "name": "Carpet Mod in Fabric", "description": "Carpet made out of fabric", From 238257f0576d0e5a79da8b2720fc307e4808a771 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 29 Jun 2019 00:52:48 -0300 Subject: [PATCH 13/19] NPE and passive spawning. fixes #39 --- .../carpet/mixins/ServerChunkManagerMixin.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java index 77713bbf..ab20320f 100644 --- a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java +++ b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java @@ -119,7 +119,7 @@ public abstract class ServerChunkManagerMixin SpawnReporter.spawn_cap_count.get(key) + mobCount); } - if (mobCount <= int_3) + if (mobCount <= int_3 || SpawnReporter.mock_spawns) { //place 0 to indicate there were spawn attempts for a category //if (entityCategory != EntityCategory.CREATURE || world.getServer().getTicks() % 400 == 0) @@ -136,6 +136,8 @@ public abstract class ServerChunkManagerMixin @Inject(method = "tickChunks", at = @At("RETURN")) private void onFinishSpawnWorldCycle(CallbackInfo ci) { + LevelProperties levelProperties_1 = this.world.getLevelProperties(); + boolean boolean_3 = levelProperties_1.getTime() % 400L == 0L; if (SpawnReporter.track_spawns > 0L && SpawnReporter.local_spawns != null) { for (EntityCategory cat: EntityCategory.values()) @@ -145,9 +147,13 @@ public abstract class ServerChunkManagerMixin int spawnTries = SpawnReporter.spawn_tries.get(cat); if (!SpawnReporter.local_spawns.containsKey(cat)) { - // fill mobcaps for that category so spawn got cancelled - SpawnReporter.spawn_ticks_full.put(key, - SpawnReporter.spawn_ticks_full.get(key)+ spawnTries); + if (!cat.isAnimal() || boolean_3) + { + // fill mobcaps for that category so spawn got cancelled + SpawnReporter.spawn_ticks_full.put(key, + SpawnReporter.spawn_ticks_full.get(key)+ spawnTries); + } + } else if (SpawnReporter.local_spawns.get(cat) > 0) { From e6158c1aabe23e49fbb69b6da3ad55f7c615801b Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 29 Jun 2019 03:05:17 -0300 Subject: [PATCH 14/19] code suggestions --- .../java/carpet/commands/ScriptCommand.java | 31 +++++++++++++++++- .../java/carpet/script/CarpetExpression.java | 25 +++++++++------ src/main/java/carpet/script/Expression.java | 2 ++ .../carpet/script/ExpressionInspector.java | 32 +++++++++++++++++++ .../script/value/NBTSerializableValue.java | 12 +++---- 5 files changed, 85 insertions(+), 17 deletions(-) diff --git a/src/main/java/carpet/commands/ScriptCommand.java b/src/main/java/carpet/commands/ScriptCommand.java index b2f0bfed..4f54e583 100644 --- a/src/main/java/carpet/commands/ScriptCommand.java +++ b/src/main/java/carpet/commands/ScriptCommand.java @@ -14,6 +14,8 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.minecraft.block.Block; import net.minecraft.block.pattern.CachedBlockPosition; import net.minecraft.command.arguments.BlockPosArgumentType; @@ -31,6 +33,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Locale; +import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; import java.util.function.Supplier; @@ -40,6 +43,31 @@ import static net.minecraft.server.command.CommandSource.suggestMatching; public class ScriptCommand { + + private static CompletableFuture suggestCode(SuggestionsBuilder suggestionsBuilder) { + String previous = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT); + int strlen = previous.length(); + StringBuilder lastToken = new StringBuilder(); + for (int idx = strlen-1; idx >=0; idx--) + { + char ch = previous.charAt(idx); + if (Character.isLetterOrDigit(ch) || ch == '_') + { + lastToken.append(ch); + } + else + { + break; + } + } + if (lastToken.length() == 0) + return suggestionsBuilder.buildFuture(); + String prefix = lastToken.reverse().toString(); + String previousString = previous.substring(0,previous.length()-prefix.length()) ; + ExpressionInspector.suggestFunctions(previousString, prefix).forEach(text -> suggestionsBuilder.suggest(previousString+text)); + return suggestionsBuilder.buildFuture(); + } + public static void register(CommandDispatcher dispatcher) { LiteralArgumentBuilder b = literal("globals"). @@ -50,7 +78,7 @@ public class ScriptCommand executes( (cc) -> { CarpetServer.scriptServer.stopAll = false; return 1;}); LiteralArgumentBuilder l = literal("run"). requires((player) -> player.hasPermissionLevel(2)). - then(argument("expr", StringArgumentType.greedyString()). + then(argument("expr", StringArgumentType.greedyString()).suggests((cc, bb) -> suggestCode(bb)). executes((cc) -> compute( cc, StringArgumentType.getString(cc, "expr")))); @@ -113,6 +141,7 @@ public class ScriptCommand then(argument("from", BlockPosArgumentType.create()). then(argument("to", BlockPosArgumentType.create()). then(argument("expr", StringArgumentType.greedyString()). + suggests((cc, bb) -> suggestCode(bb)). executes( (cc) -> scriptScan( cc, BlockPosArgumentType.getBlockPos(cc, "origin"), diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 8f84fe7c..a5bfa90d 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -101,6 +101,7 @@ public class CarpetExpression private ServerCommandSource source; private BlockPos origin; private Expression expr; + Expression getExpr() {return expr;} private static long tickStart = 0L; private static boolean stopAll = false; @@ -766,6 +767,8 @@ public class CarpetExpression this.expr.addLazyFunction("harvest", -1, (c, t, lv) -> { + if (lv.size()<2) + throw new InternalExpressionException("harvest takes at least 2 parameters: entity and block, or position, to harvest"); CarpetContext cc = (CarpetContext)c; World world = cc.s.getWorld(); Value entityValue = lv.get(0).evalValue(cc); @@ -791,14 +794,12 @@ public class CarpetExpression this.expr.addLazyFunction("place_item", -1, (c, t, lv) -> { + if (lv.size()<2) + throw new InternalExpressionException("place_item takes at least 2 parameters: item and block, or position, to place onto"); CarpetContext cc = (CarpetContext) c; String itemString = lv.get(0).evalValue(c).getString(); BlockValue.VectorLocator locator = BlockValue.locateVec(cc, lv, 1); ItemStackArgument stackArg = NBTSerializableValue.parseItem(itemString); - if (stackArg == null) - { - throw new InternalExpressionException("unknown item: "+itemString); - } BlockPos where = new BlockPos(locator.vec); String facing = "up"; if (lv.size() > locator.offset) @@ -876,6 +877,8 @@ public class CarpetExpression this.expr.addLazyFunction("inventory_get", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); + if (inventoryLocator == null) + return (_c, _t) -> Value.NULL; if (lv.size() == inventoryLocator.offset) { List fullInventory = new ArrayList<>(); @@ -897,6 +900,8 @@ public class CarpetExpression this.expr.addLazyFunction("inventory_drop", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); + if (inventoryLocator == null) + return (_c, _t) -> Value.NULL; if (lv.size() == inventoryLocator.offset) throw new InternalExpressionException("slot number is required for inventory_drop"); int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); @@ -947,16 +952,14 @@ public class CarpetExpression this.expr.addLazyFunction("inventory_find", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); + if (inventoryLocator == null) + return (_c, _t) -> Value.NULL; ItemStackArgument itemArg = null; if (lv.size() > inventoryLocator.offset) { Value secondArg = lv.get(inventoryLocator.offset+0).evalValue(c); if (!(secondArg instanceof NullValue)) - { itemArg = NBTSerializableValue.parseItem(secondArg.getString()); - if (itemArg == null) - throw new InternalExpressionException("Incorrect item format: "+secondArg.getString()); - } } int startIndex = 0; if (lv.size() > inventoryLocator.offset+1) @@ -980,7 +983,8 @@ public class CarpetExpression this.expr.addLazyFunction("inventory_set", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); - + if (inventoryLocator == null) + return (_c, _t) -> Value.NULL; if (lv.size() < inventoryLocator.offset+2) throw new InternalExpressionException("inventory_set requires at least slot number and new stack size, and optional new item"); int slot = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+0).evalValue(c)).getLong(); @@ -1019,7 +1023,8 @@ public class CarpetExpression this.expr.addLazyFunction("inventory_remove", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); - + if (inventoryLocator == null) + return (_c, _t) -> Value.NULL; if (lv.size() <= inventoryLocator.offset) throw new InternalExpressionException("inventory_set requires at least an item to be removed"); ItemStackArgument searchItem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset).evalValue(c).getString()); diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index d4f3a49c..f04693fe 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.Stack; import java.util.function.BiFunction; import java.util.function.Function; @@ -350,6 +351,7 @@ public class Expression implements Cloneable boolean isAnOperator(String opname) { return operators.containsKey(opname) || operators.containsKey(opname+"u");} private Map functions = new HashMap<>(); + Set getFunctionNames() {return functions.keySet();} //static final Map globalFunctions = new HashMap<>(); diff --git a/src/main/java/carpet/script/ExpressionInspector.java b/src/main/java/carpet/script/ExpressionInspector.java index a9edc887..0602c933 100644 --- a/src/main/java/carpet/script/ExpressionInspector.java +++ b/src/main/java/carpet/script/ExpressionInspector.java @@ -1,6 +1,13 @@ package carpet.script; +import carpet.CarpetServer; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; /** * sole purpose of this package is to provide public access to package-private methods of Expression and CarpetExpression @@ -17,4 +24,29 @@ public class ExpressionInspector { return e.getName(); } + + private static TreeSet scarpetFunctions; + private static TreeSet APIFunctions; + static + { + Set allFunctions = (new CarpetExpression("null", null, null)).getExpr().getFunctionNames(); + scarpetFunctions = new TreeSet<>(new Expression("null").getFunctionNames()); + APIFunctions = new TreeSet<>(allFunctions.stream().filter(s -> !scarpetFunctions.contains(s)).collect(Collectors.toSet())); + } + + public static List suggestFunctions(String previous, String prefix) + { + previous = previous.replace("\\'", ""); + int quoteCount = StringUtils.countMatches(previous,'\''); + if (quoteCount % 2 == 1) + return Collections.emptyList(); + int maxLen = prefix.length()<3 ? (prefix.length()*2+1) : 1234; + List scarpetMatches = scarpetFunctions.stream(). + filter(s -> s.startsWith(prefix) && s.length() <= maxLen).map(s -> s+"(").collect(Collectors.toList()); + scarpetMatches.addAll(APIFunctions.stream(). + filter(s -> s.startsWith(prefix) && s.length() <= maxLen).map(s -> s+"(").collect(Collectors.toList())); + scarpetMatches.addAll(CarpetServer.scriptServer.globalHost.globalVariables.keySet().stream(). + filter(s -> s.startsWith(prefix)).collect(Collectors.toList())); + return scarpetMatches; + } } diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java index 8e3a0efa..a7dfe4dc 100644 --- a/src/main/java/carpet/script/value/NBTSerializableValue.java +++ b/src/main/java/carpet/script/value/NBTSerializableValue.java @@ -51,7 +51,7 @@ public class NBTSerializableValue extends Value else if (e instanceof VillagerEntity) inv = ((VillagerEntity) e).getInventory(); if (inv == null) - throw new InternalExpressionException("Entity " + e + " has no inventory"); + return null; return new InventoryLocator(e, e.getBlockPos(), inv, offset + 1); } @@ -59,10 +59,10 @@ public class NBTSerializableValue extends Value { BlockPos pos = ((BlockValue) v1).getPos(); if (pos == null) - throw new InternalExpressionException("Block to acess inventory needs to be positioned in the world"); + throw new InternalExpressionException("Block to access inventory needs to be positioned in the world"); inv = HopperBlockEntity.getInventoryAt(c.s.getWorld(), pos); if (inv == null) - throw new InternalExpressionException("Block at " + pos + " has no inventory"); + return null; return new InventoryLocator(pos, pos, inv, offset + 1); } else if (v1 instanceof ListValue) @@ -74,7 +74,7 @@ public class NBTSerializableValue extends Value NumericValue.asNumber(args.get(2)).getDouble()); inv = HopperBlockEntity.getInventoryAt(c.s.getWorld(), pos); if (inv == null) - throw new InternalExpressionException("Block at " + pos + " has no inventory"); + return null; return new InventoryLocator(pos, pos, inv, offset + 1); } BlockPos pos = new BlockPos( @@ -83,7 +83,7 @@ public class NBTSerializableValue extends Value NumericValue.asNumber(params.get(2 + offset).evalValue(c)).getDouble()); inv = HopperBlockEntity.getInventoryAt(c.s.getWorld(), pos); if (inv == null) - throw new InternalExpressionException("Block at " + pos + " has no inventory"); + return null; return new InventoryLocator(pos, pos, inv, offset + 3); } catch (IndexOutOfBoundsException e) @@ -109,7 +109,7 @@ public class NBTSerializableValue extends Value } catch (CommandSyntaxException e) { - return null; + throw new InternalExpressionException("Incorrect item: "+itemString); } } From b79b9428190362038329c900a57d067f063a1c03 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 29 Jun 2019 03:29:29 -0300 Subject: [PATCH 15/19] inv size --- .../java/carpet/script/CarpetExpression.java | 21 +++++++++++++++---- src/main/java/carpet/script/Expression.java | 3 ++- .../script/value/NBTSerializableValue.java | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index a5bfa90d..434430cb 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -873,6 +873,15 @@ public class CarpetExpression public void API_InventoryManipulation() { + this.expr.addLazyFunction("inventory_size", -1, (c, t, lv) -> { + CarpetContext cc = (CarpetContext) c; + NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); + if (inventoryLocator == null) + return (_c, _t) -> Value.NULL; + Value res = new NumericValue(inventoryLocator.inventory.getInvSize()); + return (_c, _t) -> res; + }); + //inventory_get(, ) -> item_triple this.expr.addLazyFunction("inventory_get", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; @@ -890,8 +899,9 @@ public class CarpetExpression return (_c, _t) -> res; } int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); - if (slot < 0 || slot > inventoryLocator.inventory.getInvSize()) - throw new InternalExpressionException("Inventory has "+inventoryLocator.inventory.getInvSize()+" slots available"); + slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); + if (slot == inventoryLocator.inventory.getInvSize()) + return (_c, _t) -> Value.NULL; Value res = ListValue.fromItemStack(inventoryLocator.inventory.getInvStack(slot)); return (_c, _t) -> res; }); @@ -905,8 +915,9 @@ public class CarpetExpression if (lv.size() == inventoryLocator.offset) throw new InternalExpressionException("slot number is required for inventory_drop"); int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); - if (slot < 0 || slot > inventoryLocator.inventory.getInvSize()) - throw new InternalExpressionException("Inventory has "+inventoryLocator.inventory.getInvSize()+" slots available"); + slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); + if (slot == inventoryLocator.inventory.getInvSize()) + return (_c, _t) -> Value.NULL; int amount = 0; if (lv.size() > inventoryLocator.offset+1) amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); @@ -989,6 +1000,8 @@ public class CarpetExpression throw new InternalExpressionException("inventory_set requires at least slot number and new stack size, and optional new item"); int slot = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+0).evalValue(c)).getLong(); slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); + if (slot == inventoryLocator.inventory.getInvSize()) + return (_c, _t) -> Value.NULL; int count = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); if (count == 0) { diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index f04693fe..2eec66ac 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -2242,7 +2242,7 @@ public class Expression implements Cloneable * number('2')+number('2') => 4 * * - *

str(expr, params? ... )

+ *

str(expr, params? ... ), str(expr, param_list)

* *

Returns a formatted string representing expression. * Accepts formatting style accepted by String.format. @@ -2265,6 +2265,7 @@ public class Expression implements Cloneable * str('3bar') => null * str(2)+str(2) => 22 * str('pi: %.2f',pi) => 'pi: 3.14' + * str('player at: %d %d %d',pos(player())) => 'player at: 567, -2423, 124' * * *


diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java index a7dfe4dc..282364be 100644 --- a/src/main/java/carpet/script/value/NBTSerializableValue.java +++ b/src/main/java/carpet/script/value/NBTSerializableValue.java @@ -119,7 +119,7 @@ public class NBTSerializableValue extends Value if (slot < 0) slot = invSize + slot; if (slot < 0 || slot >= invSize) - throw new InternalExpressionException("Slot for inventory should be between 0 and "+(invSize-1)); + return inv.getInvSize(); // outside of inventory return slot; } From 83a8f350947e429a19a84a83e145b1b9a5aa650b Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 29 Jun 2019 20:00:15 -0300 Subject: [PATCH 16/19] better inventory and nbt support. control flow statements default to nulls --- .../java/carpet/script/CarpetExpression.java | 61 +++++++++++++++++-- src/main/java/carpet/script/Expression.java | 12 ++-- .../java/carpet/script/value/BlockValue.java | 41 ++++++++++++- .../carpet/script/value/LazyListValue.java | 6 ++ .../java/carpet/script/value/ListValue.java | 34 +++++++---- .../script/value/NBTSerializableValue.java | 59 +++++++++++++++--- .../carpet/script/value/NumericValue.java | 2 +- 7 files changed, 182 insertions(+), 33 deletions(-) diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 434430cb..e3b19e40 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -40,6 +40,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundTag; import net.minecraft.particle.ParticleEffect; import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.server.MinecraftServer; @@ -547,6 +548,20 @@ public class CarpetExpression return (c_, t_) -> retval; }); + this.expr.addLazyFunction("block_data", -1, (c, t, lv) -> + { + CarpetContext cc = (CarpetContext) c; + if (lv.size() == 0) + { + throw new InternalExpressionException("Block requires at least one parameter"); + } + CompoundTag tag = BlockValue.fromParams(cc, lv, 0, true).block.getData(); + if (tag.isEmpty()) + return (c_, t_) -> Value.NULL; + Value retval = new NBTSerializableValue(tag); + return (c_, t_) -> retval; + }); + this.expr.addLazyFunction("pos", 1, (c, t, lv) -> { Value arg = lv.get(0).evalValue(c); @@ -718,10 +733,29 @@ public class CarpetExpression sourceBlockState = setProperty(property, paramString, paramValue, sourceBlockState); } } - if (sourceBlockState == targetBlockState) + + CompoundTag data = sourceLocator.block.getData(); + + if (sourceBlockState == targetBlockState && data == null) return (c_, t_) -> Value.FALSE; CarpetSettings.impendingFillSkipUpdates = !CarpetSettings.fillUpdates; - cc.s.getWorld().setBlockState(targetLocator.block.getPos(), sourceBlockState, 2); + BlockPos targetPos = targetLocator.block.getPos(); + cc.s.getWorld().setBlockState(targetPos, sourceBlockState, 2); + + if ( data != null) + { + BlockEntity be = world.getBlockEntity(targetPos); + if (be != null) + { + CompoundTag destTag = data.method_10553(); + destTag.putInt("x", targetPos.getX()); + destTag.putInt("y", targetPos.getY()); + destTag.putInt("z", targetPos.getZ()); + be.fromTag(destTag); + be.markDirty(); + } + } + CarpetSettings.impendingFillSkipUpdates = false; Value retval = new BlockValue(sourceBlockState, world, targetLocator.block.getPos()); return (c_, t_) -> retval; @@ -873,6 +907,12 @@ public class CarpetExpression public void API_InventoryManipulation() { + this.expr.addLazyFunction("stack_limit", 1, (c, t, lv) -> { + ItemStackArgument item = NBTSerializableValue.parseItem(lv.get(0).evalValue(c).getString()); + Value res = new NumericValue(item.getItem().getMaxCount()); + return (_c, _t) -> res; + }); + this.expr.addLazyFunction("inventory_size", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); @@ -990,7 +1030,7 @@ public class CarpetExpression return (_c, _t) -> Value.NULL; }); - //inventory_set(, , , ) + //inventory_set(, , , , ) this.expr.addLazyFunction("inventory_set", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); @@ -1018,7 +1058,20 @@ public class CarpetExpression inventoryLocator.inventory.setInvStack(slot, newStack); return (_c, _t) -> ListValue.fromItemStack(previousStack); } - ItemStackArgument newitem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset+2).evalValue(c).getString()); + CompoundTag nbt = null; + if (lv.size() >= inventoryLocator.offset+3) + { + Value nbtValue = lv.get(inventoryLocator.offset+3).evalValue(c); + if (nbtValue instanceof NBTSerializableValue) + nbt = ((NBTSerializableValue)nbtValue).getTag(); + else + nbt = new NBTSerializableValue(nbtValue.getString()).getTag(); + } + ItemStackArgument newitem = NBTSerializableValue.parseItem( + lv.get(inventoryLocator.offset+2).evalValue(c).getString(), + nbt + ); + ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); try { diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 2eec66ac..5cb5c750 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -964,12 +964,14 @@ public class Expression implements Cloneable return (cc, tt) -> new StringValue("OK"); }); - addUnaryFunction("exit", (v) -> { throw new ExitStatement(v); }); - addUnaryFunction("return", (v) -> { throw new ReturnStatement(v); }); - addUnaryFunction("throw", (v)-> {throw new ThrowStatement(v); }); + addFunction("exit", (lv) -> { throw new ExitStatement(lv.size()==0?Value.NULL:lv.get(0)); }); + addFunction("return", (lv) -> { throw new ReturnStatement(lv.size()==0?Value.NULL:lv.get(0));} ); + addFunction("throw", (lv)-> {throw new ThrowStatement(lv.size()==0?Value.NULL:lv.get(0)); }); - addLazyFunction("try", 2, (c, t, lv) -> + addLazyFunction("try", -1, (c, t, lv) -> { + if (lv.size()==0) + throw new InternalExpressionException("try needs at least an expression block"); try { Value retval = lv.get(0).evalValue(c, t); @@ -977,6 +979,8 @@ public class Expression implements Cloneable } catch (ThrowStatement ret) { + if (lv.size() == 1) + return (c_, t_) -> Value.NULL; LazyValue __ = c.getVariable("_"); c.setVariable("_", (__c, __t) -> ret.retval.reboundedTo("_")); Value val = lv.get(1).evalValue(c, t); diff --git a/src/main/java/carpet/script/value/BlockValue.java b/src/main/java/carpet/script/value/BlockValue.java index 3ba7f719..2fa1dee6 100644 --- a/src/main/java/carpet/script/value/BlockValue.java +++ b/src/main/java/carpet/script/value/BlockValue.java @@ -6,10 +6,12 @@ import carpet.script.exception.InternalExpressionException; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; import net.minecraft.command.arguments.BlockArgumentParser; import net.minecraft.block.Blocks; import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; @@ -31,6 +33,7 @@ public class BlockValue extends Value private BlockState blockState; private BlockPos pos; private World world; + private CompoundTag data; public static BlockValue fromCoords(CarpetContext c, int x, int y, int z) { @@ -48,7 +51,10 @@ public class BlockValue extends Value BlockArgumentParser blockstateparser = (new BlockArgumentParser(new StringReader(str), false)).parse(true); if (blockstateparser.getBlockState() != null) { - bv = new BlockValue(blockstateparser.getBlockState(), null, null); + CompoundTag bd = blockstateparser.getNbtData(); + if (bd == null) + bd = new CompoundTag(); + bv = new BlockValue(blockstateparser.getBlockState(), null, null, bd ); if (bvCache.size()>10000) bvCache.clear(); bvCache.put(str, bv); @@ -182,11 +188,44 @@ public class BlockValue extends Value throw new InternalExpressionException("Attemted to fetch blockstate without world or stored blockstate"); } + public CompoundTag getData() + { + if (data != null) + { + if (data.isEmpty()) + return null; + return data; + } + if (world != null && pos != null) + { + BlockEntity be = world.getBlockEntity(pos); + CompoundTag tag = new CompoundTag(); + if (be == null) + { + data = tag; + return null; + } + data = be.toTag(tag); + return data; + } + throw new InternalExpressionException("Attemted to fetch block data without world or stored block data"); + } + + public BlockValue(BlockState state, World world, BlockPos position) { this.world = world; blockState = state; pos = position; + data = null; + } + + public BlockValue(BlockState state, World world, BlockPos position, CompoundTag nbt) + { + this.world = world; + blockState = state; + pos = position; + data = nbt; } diff --git a/src/main/java/carpet/script/value/LazyListValue.java b/src/main/java/carpet/script/value/LazyListValue.java index 2f1af01e..be416f18 100644 --- a/src/main/java/carpet/script/value/LazyListValue.java +++ b/src/main/java/carpet/script/value/LazyListValue.java @@ -100,4 +100,10 @@ public abstract class LazyListValue extends ListValue implements Iterator throw new InternalExpressionException("Cannot add to iterators"); } + @Override + public boolean equals(final Value o) + { + return false; + } + } diff --git a/src/main/java/carpet/script/value/ListValue.java b/src/main/java/carpet/script/value/ListValue.java index a8b20d72..fefb8a7f 100644 --- a/src/main/java/carpet/script/value/ListValue.java +++ b/src/main/java/carpet/script/value/ListValue.java @@ -203,25 +203,33 @@ public class ListValue extends Value 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; - } + if (this_size != o_size) return this_size - o_size; + if (this_size == 0) return 0; for (int i = 0; i < this_size; i++) { int res = this.items.get(i).compareTo(ol.items.get(i)); - if (res != 0) - { - return res; - } + if (res != 0) return res; } return 0; } - return super.compareTo(o); + return getString().compareTo(o.getString()); + } + + @Override + public boolean equals(final Value o) + { + if (o instanceof ListValue) + { + ListValue ol = (ListValue)o; + int this_size = this.getItems().size(); + int o_size = ol.getItems().size(); + if (this_size != o_size) return false; + if (this_size == 0) return true; + for (int i = 0; i < this_size; i++) + if (!this.items.get(i).equals(ol.items.get(i))) return false; + return true; + } + return false; } public List getItems() diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java index 282364be..2423539b 100644 --- a/src/main/java/carpet/script/value/NBTSerializableValue.java +++ b/src/main/java/carpet/script/value/NBTSerializableValue.java @@ -7,17 +7,15 @@ import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.entity.HopperBlockEntity; import net.minecraft.command.arguments.ItemStackArgument; -import net.minecraft.command.arguments.ItemStackArgumentType; import net.minecraft.command.arguments.ItemStringReader; import net.minecraft.entity.Entity; -import net.minecraft.entity.passive.AbstractTraderEntity; import net.minecraft.entity.passive.VillagerEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.Inventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.StringNbtReader; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; import java.util.HashMap; import java.util.List; @@ -26,15 +24,33 @@ import java.util.function.Supplier; public class NBTSerializableValue extends Value { - private Object what; private String nbtString = null; private CompoundTag nbtTag = null; - private Supplier nbtSupplier; + private Supplier nbtSupplier = null; public NBTSerializableValue(ItemStack stack) { - what = stack; - nbtSupplier = () -> ((ItemStack) what).toTag(new CompoundTag()); + nbtSupplier = () -> stack.hasTag() ? stack.getTag(): new CompoundTag(); + } + + public NBTSerializableValue(String nbtString) + { + nbtSupplier = () -> + { + try + { + return (new StringNbtReader(new StringReader(nbtString))).parseCompoundTag(); + } + catch (CommandSyntaxException e) + { + throw new InternalExpressionException("Incorrect nbt data: "+nbtString); + } + }; + } + + public NBTSerializableValue(CompoundTag tag) + { + nbtTag = tag; } public static InventoryLocator locateInventory(CarpetContext c, List params, int offset) @@ -93,19 +109,32 @@ public class NBTSerializableValue extends Value } private static Map itemCache = new HashMap<>(); + public static ItemStackArgument parseItem(String itemString) + { + return parseItem(itemString, null); + } + + public static ItemStackArgument parseItem(String itemString, CompoundTag customTag) { try { ItemStackArgument res = itemCache.get(itemString); if (res != null) - return res; + if (customTag == null) + return res; + else + return new ItemStackArgument(res.getItem(), customTag); + ItemStringReader parser = (new ItemStringReader(new StringReader(itemString), false)).consume(); res = new ItemStackArgument(parser.getItem(), parser.getTag()); itemCache.put(itemString, res); if (itemCache.size()>64000) itemCache.clear(); - return res; + if (customTag == null) + return res; + else + return new ItemStackArgument(res.getItem(), customTag); } catch (CommandSyntaxException e) { @@ -123,13 +152,23 @@ public class NBTSerializableValue extends Value return slot; } - private CompoundTag getTag() + public CompoundTag getTag() { if (nbtTag == null) nbtTag = nbtSupplier.get(); return nbtTag; } + @Override + public boolean equals(final Value o) + { + if (o instanceof NBTSerializableValue) + { + return getTag().equals(((NBTSerializableValue) o).getTag()); + } + return super.equals(o); + } + @Override public String getString() diff --git a/src/main/java/carpet/script/value/NumericValue.java b/src/main/java/carpet/script/value/NumericValue.java index 2a87b334..ec7bc9b2 100644 --- a/src/main/java/carpet/script/value/NumericValue.java +++ b/src/main/java/carpet/script/value/NumericValue.java @@ -116,7 +116,7 @@ public class NumericValue extends Value { return value.compareTo(((NumericValue) o).getDouble()); } - return super.compareTo(o); + return getString().compareTo(o.getString()); } @Override public boolean equals(Value o) From 5bb813be769ab9b51ea192c75574e8cfcac82af2 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 29 Jun 2019 20:39:41 -0300 Subject: [PATCH 17/19] cleanup --- .../java/carpet/commands/ScriptCommand.java | 22 +++++++++---------- .../java/carpet/script/CarpetExpression.java | 19 ++++++++++------ src/main/java/carpet/script/Expression.java | 21 +++++++++--------- .../carpet/script/ExpressionInspector.java | 9 ++++++-- .../script/value/NBTSerializableValue.java | 3 --- .../java/carpet/settings/CarpetSettings.java | 2 +- src/main/java/carpet/settings/Validator.java | 2 +- 7 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/main/java/carpet/commands/ScriptCommand.java b/src/main/java/carpet/commands/ScriptCommand.java index 4f54e583..2068990f 100644 --- a/src/main/java/carpet/commands/ScriptCommand.java +++ b/src/main/java/carpet/commands/ScriptCommand.java @@ -44,27 +44,25 @@ import static net.minecraft.server.command.CommandSource.suggestMatching; public class ScriptCommand { - private static CompletableFuture suggestCode(SuggestionsBuilder suggestionsBuilder) { + private static CompletableFuture suggestCode( + CommandContext context, + SuggestionsBuilder suggestionsBuilder + ) + { + ScriptHost currentHost = getHost(context); String previous = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT); int strlen = previous.length(); StringBuilder lastToken = new StringBuilder(); for (int idx = strlen-1; idx >=0; idx--) { char ch = previous.charAt(idx); - if (Character.isLetterOrDigit(ch) || ch == '_') - { - lastToken.append(ch); - } - else - { - break; - } + if (Character.isLetterOrDigit(ch) || ch == '_') lastToken.append(ch); else break; } if (lastToken.length() == 0) return suggestionsBuilder.buildFuture(); String prefix = lastToken.reverse().toString(); String previousString = previous.substring(0,previous.length()-prefix.length()) ; - ExpressionInspector.suggestFunctions(previousString, prefix).forEach(text -> suggestionsBuilder.suggest(previousString+text)); + ExpressionInspector.suggestFunctions(currentHost, previousString, prefix).forEach(text -> suggestionsBuilder.suggest(previousString+text)); return suggestionsBuilder.buildFuture(); } @@ -78,7 +76,7 @@ public class ScriptCommand executes( (cc) -> { CarpetServer.scriptServer.stopAll = false; return 1;}); LiteralArgumentBuilder l = literal("run"). requires((player) -> player.hasPermissionLevel(2)). - then(argument("expr", StringArgumentType.greedyString()).suggests((cc, bb) -> suggestCode(bb)). + then(argument("expr", StringArgumentType.greedyString()).suggests((cc, bb) -> suggestCode(cc, bb)). executes((cc) -> compute( cc, StringArgumentType.getString(cc, "expr")))); @@ -141,7 +139,7 @@ public class ScriptCommand then(argument("from", BlockPosArgumentType.create()). then(argument("to", BlockPosArgumentType.create()). then(argument("expr", StringArgumentType.greedyString()). - suggests((cc, bb) -> suggestCode(bb)). + suggests((cc, bb) -> suggestCode(cc, bb)). executes( (cc) -> scriptScan( cc, BlockPosArgumentType.getBlockPos(cc, "origin"), diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index e3b19e40..4f63e39e 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -866,7 +866,6 @@ public class CarpetExpression BlockSoundGroup blockSoundGroup = placementState.getSoundGroup(); cc.s.getWorld().playSound(null, where, blockSoundGroup.getPlaceSound(), SoundCategory.BLOCKS, (blockSoundGroup.getVolume() + 1.0F) / 2.0F, blockSoundGroup.getPitch() * 0.8F); return (_c, _t) -> Value.TRUE; - } } } @@ -907,13 +906,15 @@ public class CarpetExpression public void API_InventoryManipulation() { - this.expr.addLazyFunction("stack_limit", 1, (c, t, lv) -> { + this.expr.addLazyFunction("stack_limit", 1, (c, t, lv) -> + { ItemStackArgument item = NBTSerializableValue.parseItem(lv.get(0).evalValue(c).getString()); Value res = new NumericValue(item.getItem().getMaxCount()); return (_c, _t) -> res; }); - this.expr.addLazyFunction("inventory_size", -1, (c, t, lv) -> { + this.expr.addLazyFunction("inventory_size", -1, (c, t, lv) -> + { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); if (inventoryLocator == null) @@ -923,7 +924,8 @@ public class CarpetExpression }); //inventory_get(, ) -> item_triple - this.expr.addLazyFunction("inventory_get", -1, (c, t, lv) -> { + this.expr.addLazyFunction("inventory_get", -1, (c, t, lv) -> + { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); if (inventoryLocator == null) @@ -947,7 +949,8 @@ public class CarpetExpression }); //inventory_drop(, , ) -> entity_item (and sets slot) or null if cannot - this.expr.addLazyFunction("inventory_drop", -1, (c, t, lv) -> { + this.expr.addLazyFunction("inventory_drop", -1, (c, t, lv) -> + { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); if (inventoryLocator == null) @@ -1000,7 +1003,8 @@ public class CarpetExpression }); //inventory_find(, or null (first empty slot), ) -> or null - this.expr.addLazyFunction("inventory_find", -1, (c, t, lv) -> { + this.expr.addLazyFunction("inventory_find", -1, (c, t, lv) -> + { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); if (inventoryLocator == null) @@ -1031,7 +1035,8 @@ public class CarpetExpression }); //inventory_set(, , , , ) - this.expr.addLazyFunction("inventory_set", -1, (c, t, lv) -> { + this.expr.addLazyFunction("inventory_set", -1, (c, t, lv) -> + { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); if (inventoryLocator == null) diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 5cb5c750..2468efef 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -1840,11 +1840,10 @@ public class Expression implements Cloneable return LazyListValue.range(from, to, step); }); - addBinaryFunction("get", (v1, v2) -> { + addBinaryFunction("get", (v1, v2) -> + { if (v1 instanceof LazyListValue || !(v1 instanceof ListValue)) - { throw new InternalExpressionException("First argument of element should be a list"); - } List items = ((ListValue)v1).getItems(); long index = NumericValue.asNumber(v2).getLong(); int numitems = items.size(); @@ -1854,12 +1853,11 @@ public class Expression implements Cloneable return items.get((int)index); }); - //Deprecated - addBinaryFunction("element", (v1, v2) -> { + //Deprecated, use "get" instead + addBinaryFunction("element", (v1, v2) -> + { if (v1 instanceof LazyListValue || !(v1 instanceof ListValue)) - { throw new InternalExpressionException("First argument of element should be a list"); - } List items = ((ListValue)v1).getItems(); long index = NumericValue.asNumber(v2).getLong(); int numitems = items.size(); @@ -1868,6 +1866,7 @@ public class Expression implements Cloneable index = index % numitems; return items.get((int)index); }); + addFunction("put", (lv) -> { if(lv.size()<3) @@ -2777,10 +2776,10 @@ public class Expression implements Cloneable { return exit.retval; } - //catch (StackOverflowError ignored) - //{ - // throw new ExpressionException("Your thoughts are too deep"); - //} + catch (StackOverflowError ignored) + { + throw new ExpressionException("Your thoughts are too deep"); + } catch (InternalExpressionException exc) { throw new ExpressionException("Your expression result is incorrect:"+exc.getMessage()); diff --git a/src/main/java/carpet/script/ExpressionInspector.java b/src/main/java/carpet/script/ExpressionInspector.java index 0602c933..56d602c5 100644 --- a/src/main/java/carpet/script/ExpressionInspector.java +++ b/src/main/java/carpet/script/ExpressionInspector.java @@ -34,7 +34,7 @@ public class ExpressionInspector APIFunctions = new TreeSet<>(allFunctions.stream().filter(s -> !scarpetFunctions.contains(s)).collect(Collectors.toSet())); } - public static List suggestFunctions(String previous, String prefix) + public static List suggestFunctions(ScriptHost host, String previous, String prefix) { previous = previous.replace("\\'", ""); int quoteCount = StringUtils.countMatches(previous,'\''); @@ -45,7 +45,12 @@ public class ExpressionInspector filter(s -> s.startsWith(prefix) && s.length() <= maxLen).map(s -> s+"(").collect(Collectors.toList()); scarpetMatches.addAll(APIFunctions.stream(). filter(s -> s.startsWith(prefix) && s.length() <= maxLen).map(s -> s+"(").collect(Collectors.toList())); - scarpetMatches.addAll(CarpetServer.scriptServer.globalHost.globalVariables.keySet().stream(). + // not that useful in commandline, more so in external scripts, so skipping here + //scarpetMatches.addAll(CarpetServer.scriptServer.events.eventHandlers.keySet().stream(). + // filter(s -> s.startsWith(prefix) && s.length() <= maxLen).map(s -> "__"+s+"(").collect(Collectors.toList())); + scarpetMatches.addAll(host.globalFunctions.keySet().stream(). + filter(s -> s.startsWith(prefix)).map(s -> s+"(").collect(Collectors.toList())); + scarpetMatches.addAll(host.globalVariables.keySet().stream(). filter(s -> s.startsWith(prefix)).collect(Collectors.toList())); return scarpetMatches; } diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java index 2423539b..14d72f80 100644 --- a/src/main/java/carpet/script/value/NBTSerializableValue.java +++ b/src/main/java/carpet/script/value/NBTSerializableValue.java @@ -163,13 +163,10 @@ public class NBTSerializableValue extends Value public boolean equals(final Value o) { if (o instanceof NBTSerializableValue) - { return getTag().equals(((NBTSerializableValue) o).getTag()); - } return super.equals(o); } - @Override public String getString() { diff --git a/src/main/java/carpet/settings/CarpetSettings.java b/src/main/java/carpet/settings/CarpetSettings.java index 835c6e35..f99044b1 100644 --- a/src/main/java/carpet/settings/CarpetSettings.java +++ b/src/main/java/carpet/settings/CarpetSettings.java @@ -204,7 +204,7 @@ public class CarpetSettings @Rule(desc = "Enables /script command", extra = "An in-game scripting API for Scarpet programming language", category = COMMAND) public static boolean commandScript = true; - @Rule(desc = "Enables /player command to control/spawn players", category = COMMAND) + @Rule(desc = "Enables /player command to control/spawn players", category = COMMAND, validate = Validator.WIP.class) public static boolean commandPlayer = true; @Rule(desc = "Placing carpets may issue carpet commands for non-op players", category = SURVIVAL) diff --git a/src/main/java/carpet/settings/Validator.java b/src/main/java/carpet/settings/Validator.java index 98d6f084..8d0ea4e2 100644 --- a/src/main/java/carpet/settings/Validator.java +++ b/src/main/java/carpet/settings/Validator.java @@ -47,7 +47,7 @@ public abstract class Validator if (source != null) try { - Messenger.m(source, "r Work in progress - limited or no functionality available for "+currentRule.name); + Messenger.m(source, "r "+currentRule.name+" not yet fully implemented - we are still working on it."); } catch (NullPointerException ignored) { } return newValue; From dca72f603b80eae3dca8e006b18a3521304010c5 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sun, 30 Jun 2019 00:51:12 -0300 Subject: [PATCH 18/19] touchups and docs --- .gitignore | 1 + .../java/carpet/script/CarpetExpression.java | 312 ++++++++++++------ src/main/java/carpet/script/Expression.java | 25 +- .../java/carpet/script/value/BlockValue.java | 2 +- src/main/java/carpet/settings/Validator.java | 2 +- 5 files changed, 234 insertions(+), 108 deletions(-) diff --git a/.gitignore b/.gitignore index 2105712d..7c9ff93b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ build/ out/ classes/ publish/ +docs/ # idea diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 4f63e39e..c9eeb038 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -281,12 +281,13 @@ public class CarpetExpression *

Specifying blocks

*

block(x, y, z), block(state)

*

Returns either a block from specified location, or block with a specific state - * (as used by /setblock command), so allowing for block properties etc. - * Blocks can be referenced everywhere by its simple name, but its only used in its default state

+ * (as used by /setblock command), so allowing for block properties, block entity data etc. + * Blocks otherwise can be referenced everywhere by its simple string name, but its only used in its default state

*
      * block('air')  => air
      * block('iron_trapdoor[half=top]')  => iron_trapdoor
      * block(0,0,0) == block('bedrock')  => 1
+     * block('hopper[facing=north]{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') => hopper
      * 
*

World Manipulation

*

All the functions below can be used with block value, queried with coord triple, or 3-long list. @@ -315,6 +316,21 @@ public class CarpetExpression * set(x,y,z,'iron_trapdoor[half=top]') // Incorrect. sets bottom iron trapdoor - no parsing of properties * set(x,y,z,'iron_trapdoor','half','top') // correct - top trapdoor * set(x,y,z,block('iron_trapdoor[half=top]')) // also correct, block() provides extra parsing + * set(x,y,z,'hopper[facing=north]{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') // extra block data + * + *

place_item(item, pos, facing?, sneak?)

+ *

Places a given item in the world like it was placed by a player. Item names are default minecraft item name, + * less the minecraft prefix. Default facing is 'up', but there are other options: 'down', 'north', 'east', + * 'south', 'west', but also there are other secondary directions important for placement of blocks like stairs, doors, etc. + * Try experiment with options like 'north-up' which is placed facing north with cursor pointing to the upper part of the block, + * or 'up-north', which means a block placed facing up (player looking down) and placed smidge away of the block center + * towards north. Optional sneak is a boolean indicating if a player would be sneaking while placing the block - + * this option only affects placement of chests and scaffolding at the moment. + * Returns true if placement was successful, false otherwise.

+ *
+     *     place_item('stone',x,y,z) // places a stone block on x,y,z block
+     *     place_item('piston,x,y,z,'down') // places a piston facing down
+     *     place_item('carrot',x,y,z) // attempts to plant a carrot plant. Returns true if could place carrots at that position.
      * 
*

update(pos)

*

Causes a block update at position.

@@ -352,7 +368,12 @@ public class CarpetExpression * property(block('iron_trapdoor[half=top]'),'powered') => false * bool(property(block('iron_trapdoor[half=top]'),'powered')) => 0 * - * + *

block_data(pos)

+ *

Return NBT string associated with specific location, or null if the block does not carry block data. + * Can be currently used to match specific information from it, or use it to copy to another block

+ *
+     *     block_data(x,y,z) => '{TransferCooldown:0,x:450,y:68, ... }'
+     * 
*

solid(pos)

*

Boolean function, true if the block is solid

*

air(pos)

@@ -904,6 +925,87 @@ public class CarpetExpression } + /** + *

Inventory and Items API

+ *
+ *

Manipulating inventories of blocks and entities

+ *

Most functions in this category require inventory as the first argument. Inventory could be specified by + * an entity, or a block, or position (three coordinates) of a potential block with inventory. + * If the entity or a block doesn't + * have an inventory, they typically do nothing and return null.

+ *

Most items returned are in the form of + * a triple of item name, count, and nbt or the extra data associated with an item. + * Manipulating of the nbt data can be costly, but retrieving them from the tuple to match other aspects is cheap

+ *

stack_limit(item)

+ *

Returns number indicating what is the stack limit for the item. Its typically 1 (non-stackable), + * 16 (like buckets), or 64 - rest. It is recommended to consult this, as other inventory API functions + * ignore normal stack limits, and it is up to the programmer to keep it at bay. As of 1.13, game checks for negative + * numbers and setting an item to negative is the same as empty.

+ *
+     *     stack_limit('wooden_axe') => 1
+     *     stack_limit('ender_pearl') => 16
+     *     stack_limit('stone') => 64
+     * 
+ *

inventory_size(inventory)

+ *

Returns the size of the inventory for the entity or block in question. Returns null if the block or entity + * don't have an inventory

+ *
+     *     inventory_size(player()) => 41
+     *     inventory_size(x,y,z) => 27 // chest
+     *     inventory_size(block(pos)) => 5 // hopper
+     * 
+ *

inventory_get(inventory, slot)

+ *

Returns the item in the corresponding inventory slot, or null if slot empty or inventory is invalid. + * You can use negative numbers to indicate slots counted from 'the back'.

+ *
+     *     inventory_get(player(), 0) => null // nothing in first hotbar slot
+     *     inventory_get(x,y,z, 5) => ['stone', 1, {}]
+     *     inventory_get(player(), -1) => ['diamond_pickaxe', 1, {Damage:4}] // slightly damaged diamond pick in the offhand
+     * 
+ * + *

inventory_set(inventory, slot, count, item?, nbt?)

+ *

Modifies or sets a stack in inventory. specify count 0 to empty the slot. + * If item is not specified, keeps existing item, just modifies the count. If item is provided - replaces current item. + * If nbt is provided - adds a tag to the stack at slot. Returns previous stack in that slot.

+ *
+     *     inventory_set(player(), 0, 0) => ['stone', 64, {}] // player had a stack of stone in first hotbar slot
+     *     inventory_set(player(), 0, 6) => ['diamond', 64, {}] // changed stack of diamonds in player slot to 6
+     *     inventory_set(player(), 0, 1, 'diamond_axe','{Damage:5}') => null //added slightly damaged pick to first player slot
+     * 
+ * + *

inventory_find(inventory, item, start_slot?, ), inventory_find(inventory, null, start_slot?)

+ *

Finds the first slot with a corresponding item in the inventory, or if queried with null: the first empty slot. + * Returns slot number if found, or null otherwise. Optional start_slot argument allows to skip all preceeding slots + * allowing for efficient (so not slot-by-slot) inventory search for items.

+ *
+     *     inventory_find(player(), 'stone') => 0 // player has stone in first hotbar slot
+     *     inventory_find(player(), null) => null // player's inventory has no empty spot
+     *     while( (slot = inventory_find(p, 'diamond', slot)) != null, 41, drop_item(p, slot) )
+     *         // spits all diamonds from player inventory wherever they are
+     *     inventory_drop(x,y,z, 0) => 64 // removed and spawned in the world a full stack of items
+     * 
+ * + *

inventory_remove(inventory, item, amount?)

+ *

Removes amount (defaults to 1) of item from inventory. If the inventory doesn't have the defined amount, nothing + * happens, otherwise the given amount of items is removed wherever they are in the inventory. Returns boolean whether + * the removal operation was successful. Easiest way to remove a specific item from player inventory without specifying + * the slot.

+ *
+     *     inventory_remove(player(), 'diamond') => 1 // removed diamond from player inventory
+     *     inventory_remove(player(), 'diamond', 100) => 0 // player doesn't have 100 diamonds, nothing happened
+     * 
+ * + *

drop_item(inventory, slot, amount?, )

+ *

Drops the items from indicated inventory slot, like player that Q's an item or villager, that exchanges food. + * You can Q items from block inventories as well. default amount is 0 - which is all from the slot. NOTE: hoppers are quick + * enough to pick all the queued items from their inventory anyways. + * Returns size of the actual dropped items.

+ *
+     *     inventory_drop(player(), 0, 1) => 1 // Q's one item on the ground
+     *     inventory_drop(x,y,z, 0) => 64 // removed and spawned in the world a full stack of items
+     * 
+ *
+ */ public void API_InventoryManipulation() { this.expr.addLazyFunction("stack_limit", 1, (c, t, lv) -> @@ -948,58 +1050,59 @@ public class CarpetExpression return (_c, _t) -> res; }); - //inventory_drop(, , ) -> entity_item (and sets slot) or null if cannot - this.expr.addLazyFunction("inventory_drop", -1, (c, t, lv) -> + //inventory_set(, , , , ) + this.expr.addLazyFunction("inventory_set", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); if (inventoryLocator == null) return (_c, _t) -> Value.NULL; - if (lv.size() == inventoryLocator.offset) - throw new InternalExpressionException("slot number is required for inventory_drop"); - int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); + if (lv.size() < inventoryLocator.offset+2) + throw new InternalExpressionException("inventory_set requires at least slot number and new stack size, and optional new item"); + int slot = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+0).evalValue(c)).getLong(); slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); if (slot == inventoryLocator.inventory.getInvSize()) return (_c, _t) -> Value.NULL; - int amount = 0; - if (lv.size() > inventoryLocator.offset+1) - amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); - if (amount < 0) - throw new InternalExpressionException("Cannot throw negative number of items"); - ItemStack stack = inventoryLocator.inventory.getInvStack(slot); - if (stack == null || stack.isEmpty()) - return (_c, _t) -> Value.ZERO; - if (amount == 0) - amount = stack.getCount(); - ItemStack droppedStack = inventoryLocator.inventory.takeInvStack(slot, amount); - if (droppedStack.isEmpty()) + int count = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); + if (count == 0) { - return (_c, _t) -> Value.ZERO; + // clear slot + ItemStack removedStack = inventoryLocator.inventory.removeInvStack(slot); + //Value res = ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares + return (_c, _t) -> ListValue.fromItemStack(removedStack); } - Object owner = inventoryLocator.owner; - ItemEntity item; - if (owner instanceof PlayerEntity) - item = ((PlayerEntity) owner).dropItem(droppedStack, false, true); - else if (owner instanceof LivingEntity) + if (lv.size() < inventoryLocator.offset+3) { - LivingEntity villager = (LivingEntity)owner; - // stolen from LookTargetUtil.give((VillagerEntity)owner, droppedStack, (LivingEntity) owner); - double double_1 = villager.y - 0.30000001192092896D + (double)villager.getStandingEyeHeight(); - item = new ItemEntity(villager.world, villager.x, double_1, villager.z, droppedStack); - Vec3d vec3d_1 = villager.getRotationVec(1.0F).normalize().multiply(0.3);// new Vec3d(0, 0.3, 0); - item.setVelocity(vec3d_1); - item.setToDefaultPickupDelay(); + ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); + ItemStack newStack = previousStack.copy(); + newStack.setCount(count); + inventoryLocator.inventory.setInvStack(slot, newStack); + return (_c, _t) -> ListValue.fromItemStack(previousStack); } - else + CompoundTag nbt = null; // skipping one argument + if (lv.size() > inventoryLocator.offset+3) { - Vec3d point = new Vec3d(inventoryLocator.position); - item = new ItemEntity(cc.s.getWorld(), point.x+0.5, point.y+0.5, point.z+0.5, droppedStack); - item.setToDefaultPickupDelay(); + Value nbtValue = lv.get(inventoryLocator.offset+3).evalValue(c); + if (nbtValue instanceof NBTSerializableValue) + nbt = ((NBTSerializableValue)nbtValue).getTag(); + else + nbt = new NBTSerializableValue(nbtValue.getString()).getTag(); } - inventoryLocator.inventory.markDirty(); - cc.s.getWorld().spawnEntity(item); - Value res = new NumericValue(item.getStack().getCount()); - return (_c, _t) -> res; + ItemStackArgument newitem = NBTSerializableValue.parseItem( + lv.get(inventoryLocator.offset+2).evalValue(c).getString(), + nbt + ); + + ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); + try + { + inventoryLocator.inventory.setInvStack(slot, newitem.createStack(count, false)); + } + catch (CommandSyntaxException e) + { + throw new InternalExpressionException(e.getMessage()); + } + return (_c, _t) -> ListValue.fromItemStack(previousStack); }); //inventory_find(, or null (first empty slot), ) -> or null @@ -1034,60 +1137,7 @@ public class CarpetExpression return (_c, _t) -> Value.NULL; }); - //inventory_set(, , , , ) - this.expr.addLazyFunction("inventory_set", -1, (c, t, lv) -> - { - CarpetContext cc = (CarpetContext) c; - NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); - if (inventoryLocator == null) - return (_c, _t) -> Value.NULL; - if (lv.size() < inventoryLocator.offset+2) - throw new InternalExpressionException("inventory_set requires at least slot number and new stack size, and optional new item"); - int slot = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+0).evalValue(c)).getLong(); - slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); - if (slot == inventoryLocator.inventory.getInvSize()) - return (_c, _t) -> Value.NULL; - int count = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); - if (count == 0) - { - // clear slot - ItemStack removedStack = inventoryLocator.inventory.removeInvStack(slot); - //Value res = ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares - return (_c, _t) -> ListValue.fromItemStack(removedStack); - } - if (lv.size() < inventoryLocator.offset+3) - { - ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); - ItemStack newStack = previousStack.copy(); - newStack.setCount(count); - inventoryLocator.inventory.setInvStack(slot, newStack); - return (_c, _t) -> ListValue.fromItemStack(previousStack); - } - CompoundTag nbt = null; - if (lv.size() >= inventoryLocator.offset+3) - { - Value nbtValue = lv.get(inventoryLocator.offset+3).evalValue(c); - if (nbtValue instanceof NBTSerializableValue) - nbt = ((NBTSerializableValue)nbtValue).getTag(); - else - nbt = new NBTSerializableValue(nbtValue.getString()).getTag(); - } - ItemStackArgument newitem = NBTSerializableValue.parseItem( - lv.get(inventoryLocator.offset+2).evalValue(c).getString(), - nbt - ); - ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); - try - { - inventoryLocator.inventory.setInvStack(slot, newitem.createStack(count, false)); - } - catch (CommandSyntaxException e) - { - throw new InternalExpressionException(e.getMessage()); - } - return (_c, _t) -> ListValue.fromItemStack(previousStack); - }); //inventory_remove(, , ) -> bool @@ -1134,6 +1184,63 @@ public class CarpetExpression throw new InternalExpressionException("Something bad happened - cannot pull all items from inventory"); return (_c, _t) -> Value.TRUE; }); + + //inventory_drop(, , ) -> entity_item (and sets slot) or null if cannot + this.expr.addLazyFunction("drop_item", -1, (c, t, lv) -> + { + CarpetContext cc = (CarpetContext) c; + NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); + if (inventoryLocator == null) + return (_c, _t) -> Value.NULL; + if (lv.size() == inventoryLocator.offset) + throw new InternalExpressionException("slot number is required for inventory_drop"); + int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); + slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); + if (slot == inventoryLocator.inventory.getInvSize()) + return (_c, _t) -> Value.NULL; + int amount = 0; + if (lv.size() > inventoryLocator.offset+1) + amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); + if (amount < 0) + throw new InternalExpressionException("Cannot throw negative number of items"); + ItemStack stack = inventoryLocator.inventory.getInvStack(slot); + if (stack == null || stack.isEmpty()) + return (_c, _t) -> Value.ZERO; + if (amount == 0) + amount = stack.getCount(); + ItemStack droppedStack = inventoryLocator.inventory.takeInvStack(slot, amount); + if (droppedStack.isEmpty()) + { + return (_c, _t) -> Value.ZERO; + } + Object owner = inventoryLocator.owner; + ItemEntity item; + if (owner instanceof PlayerEntity) + { + item = ((PlayerEntity) owner).dropItem(droppedStack, false, true); + } + else if (owner instanceof LivingEntity) + { + LivingEntity villager = (LivingEntity)owner; + // stolen from LookTargetUtil.give((VillagerEntity)owner, droppedStack, (LivingEntity) owner); + double double_1 = villager.y - 0.30000001192092896D + (double)villager.getStandingEyeHeight(); + item = new ItemEntity(villager.world, villager.x, double_1, villager.z, droppedStack); + Vec3d vec3d_1 = villager.getRotationVec(1.0F).normalize().multiply(0.3);// new Vec3d(0, 0.3, 0); + item.setVelocity(vec3d_1); + item.setToDefaultPickupDelay(); + cc.s.getWorld().spawnEntity(item); + } + else + { + Vec3d point = new Vec3d(inventoryLocator.position); + item = new ItemEntity(cc.s.getWorld(), point.x+0.5, point.y+0.5, point.z+0.5, droppedStack); + item.setToDefaultPickupDelay(); + cc.s.getWorld().spawnEntity(item); + } + inventoryLocator.inventory.markDirty(); + Value res = new NumericValue(item.getStack().getCount()); + return (_c, _t) -> res; + }); } @@ -1185,6 +1292,12 @@ public class CarpetExpression *

Unlike with blocks, that use plethora of vastly different querying functions, entities are queried with * query function and altered via modify function. Type of information needed or * values to be modified are different for each call

+ *

Using ~ (in) operator is an alias for query. Especially useful if a statement has + * no arguments, which in this case can be radically simplified

+ *
+     *     query(p, 'name') <=> p ~ 'name'     // much shorter and cleaner
+     *     query(p, 'holds', 'offhand') <=> p ~ l('holds', 'offhand')    // not really but can be done
+     * 
*

query(e,'removed')

*

Boolean. True if the entity is removed

*

query(e,'id')

@@ -1295,6 +1408,12 @@ public class CarpetExpression *
  • feet
  • * *

    If slot is not specified, it defaults to the main hand.

    + *

    query(e,'selected_slot')

    + *

    Number indicating the selected slot of entity inventory. Currently only applicable to players.

    + *

    query(e,'facing', order?)

    + *

    Returns where the entity is facing. optional order (number from 0 to 5, and negative), indicating + * primary directions where entity is looking at. From most prominent (order 0) to opposite (order 5, or -1)

    + * *

    query(e,'nbt',path?)

    *

    Returns full NBT of the entity. If path is specified, it fetches only that portion of the NBT, * that corresponds to the path. For specification of path attribute, consult @@ -2419,6 +2538,7 @@ public class CarpetExpression *

    The last method is the one that world edit is using (part of carpet mod). It turns out that the outline method with 32.5 radius, * fill method with round function and draw command are equivalent

    *
    + * @param host . * @param x . * @param y . * @param z . @@ -2461,12 +2581,14 @@ public class CarpetExpression /** *

    /script run command

    *
    - *

    primary way to input commands. The command executes in the context, position, and dimension of the executing + *

    Primary way to input commands. The command executes in the context, position, and dimension of the executing * player, commandblock, etc... The command receives 4 variables, x, y, z * and p indicating position and the executing entity of the command. + * You will receive tab completion suggestions as you type your code suggesting functions and global variables. * It is advisable to use /execute in ... at ... as ... run script run ... or similar, to simulate running * commands in a different scope

    *
    + * @param host . * @param pos . * @return . */ diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 2468efef..fe02649a 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -859,9 +859,10 @@ public class Expression implements Cloneable *

    Ability to combine more statements into one expression, with functions, passing parameters, and global and outer * scoping allow to organize even larger scripts

    *

    Control flow

    - *

    return(expr)

    + *

    return(expr?)

    *

    Sometimes its convenient to break the organized control flow, or it is not practical to pass * the final result value of a function to the last statement, in this case a return statement can be used

    + *

    If no argument is provided - returns null value.

    *
          * def() -> (
          *  expr1;
    @@ -873,12 +874,14 @@ public class Expression implements Cloneable
          * 
    *

    In general its cheaper to leave the last expression as a return value, rather than calling returns everywhere, * but it would often lead to a messy code.

    - *

    exit(expr)

    - *

    It terminates entire program passing expr as the result of the program execution.

    - *

    try(expr, catch_expr(_)) ... throw(value)

    + *

    exit(expr?)

    + *

    It terminates entire program passing expr as the result of the program execution, or null if omitted.

    + *

    try(expr, catch_expr(_)?) ... throw(value?)

    *

    try function evaluates expression, and continues further unless throw function is called * anywhere inside expr. In that case the catch_expr is evaluates with _ set - * to the argument throw was called with. This mechanism allows to terminate large portion of a convoluted + * to the argument throw was called with. + * This mechanic accepts skipping thrown value - it throws null instead, and catch expression - then try returns null as well + * This mechanism allows to terminate large portion of a convoluted * call stack and continue program execution. There is only one level of exceptions currently in carpet, so if the inner * function also defines the try catchment area, it will received the exception first, but it can technically * rethrow the value its getting for the outer scope. Unhandled throw acts like an exit statement.

    @@ -1620,15 +1623,15 @@ public class Expression implements Cloneable * range(20, 10, -2) => [20, 18, 16, 14, 12] * * - *

    element(list, index)

    + *

    get(list, index), element(list, index)(deprecated)

    *

    Returns the value at index element from the list. - * use negative numbers to reach elements from the end of the list. element + * use negative numbers to reach elements from the end of the list. get * call will always be able to find the index. In case there is few items, it will loop over

    *
    -     *     element(l(range(10)), 5)  => 5
    -     *     element(l(range(10)), -1)  => 9
    -     *     element(l(range(10)), 10)  => 0
    -     *     element(l(range(10)), 93)  => 3
    +     *     get(l(range(10)), 5)  => 5
    +     *     get(l(range(10)), -1)  => 9
    +     *     get(l(range(10)), 10)  => 0
    +     *     get(l(range(10)), 93)  => 3
          * 
    * *

    put(list, index, values ...), put(list, null, values ...)

    diff --git a/src/main/java/carpet/script/value/BlockValue.java b/src/main/java/carpet/script/value/BlockValue.java index 2fa1dee6..d08097ef 100644 --- a/src/main/java/carpet/script/value/BlockValue.java +++ b/src/main/java/carpet/script/value/BlockValue.java @@ -298,7 +298,7 @@ public class BlockValue extends Value DOWNNORTH ("down-north", 0.5, 1.0, 0.4, Direction.DOWN), DOWNSOUTH ("down-south", 0.5, 1.0, 0.6, Direction.DOWN), - DOWNEAST("dow-neast", 0.6, 1.0, 0.5, Direction.DOWN), + DOWNEAST("down-east", 0.6, 1.0, 0.5, Direction.DOWN), DOWNWEST("down-west", 0.4, 1.0, 0.5, Direction.DOWN), diff --git a/src/main/java/carpet/settings/Validator.java b/src/main/java/carpet/settings/Validator.java index 8d0ea4e2..66ca79cf 100644 --- a/src/main/java/carpet/settings/Validator.java +++ b/src/main/java/carpet/settings/Validator.java @@ -47,7 +47,7 @@ public abstract class Validator if (source != null) try { - Messenger.m(source, "r "+currentRule.name+" not yet fully implemented - we are still working on it."); + Messenger.m(source, "r "+currentRule.name+" is not yet fully implemented - we are still working on it."); } catch (NullPointerException ignored) { } return newValue; From b96e8e8da4b657fab4c51e3eaaa6fdabdf6ff16e Mon Sep 17 00:00:00 2001 From: gnembon Date: Tue, 2 Jul 2019 09:08:27 -0300 Subject: [PATCH 19/19] touchups and docs --- src/main/java/carpet/script/Expression.java | 4 ++-- src/main/java/carpet/script/value/BlockValue.java | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index fe02649a..1410f39e 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -1846,7 +1846,7 @@ public class Expression implements Cloneable addBinaryFunction("get", (v1, v2) -> { if (v1 instanceof LazyListValue || !(v1 instanceof ListValue)) - throw new InternalExpressionException("First argument of element should be a list"); + throw new InternalExpressionException("First argument of get should be a list"); List items = ((ListValue)v1).getItems(); long index = NumericValue.asNumber(v2).getLong(); int numitems = items.size(); @@ -1860,7 +1860,7 @@ public class Expression implements Cloneable addBinaryFunction("element", (v1, v2) -> { if (v1 instanceof LazyListValue || !(v1 instanceof ListValue)) - throw new InternalExpressionException("First argument of element should be a list"); + throw new InternalExpressionException("First argument of get should be a list"); List items = ((ListValue)v1).getItems(); long index = NumericValue.asNumber(v2).getLong(); int numitems = items.size(); diff --git a/src/main/java/carpet/script/value/BlockValue.java b/src/main/java/carpet/script/value/BlockValue.java index d08097ef..5d3ec2a8 100644 --- a/src/main/java/carpet/script/value/BlockValue.java +++ b/src/main/java/carpet/script/value/BlockValue.java @@ -349,14 +349,17 @@ public class BlockValue extends Value this.sneakPlace = sneakPlace; } + @Override public BlockPos getBlockPos() { return this.hit.getBlockPos(); } + @Override public Direction getPlayerLookDirection() { return facing.getOpposite(); } + @Override public Direction[] getPlacementDirections() { switch(this.facing) { case DOWN: @@ -375,14 +378,17 @@ public class BlockValue extends Value } } + @Override public Direction getPlayerFacing() { return this.facing.getAxis() == Direction.Axis.Y ? Direction.NORTH : this.facing; } + @Override public boolean isPlayerSneaking() { return sneakPlace; } + @Override public float getPlayerYaw() { return (float)(this.facing.getHorizontal() * 90); }