diff --git a/docs/scarpet/api/Inventories.md b/docs/scarpet/api/Inventories.md index e2a68f18..1ecc692b 100644 --- a/docs/scarpet/api/Inventories.md +++ b/docs/scarpet/api/Inventories.md @@ -3,29 +3,30 @@ ## 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. Player enderchest inventory require -two arguments, keyword `'enderchest'`, followed by the player entity argument, or a single argument as a string of a -form: `'enderchest_steve'`. If your player name starts with enderchest, it can be always accessed by passing a player +or a block, or position (three coordinates) of a potential block with inventory, or can be preceded with inventory +type. +Inventory type can be `null` (default), `'enderchest'` denoting player enderchest storage, or `'equipment'` applying to +entities hand and armour pieces. Then the type can be followed by entity, block or position coordinates. +For instance, player enderchest inventory requires +two arguments, keyword `'enderchest'`, followed by the player entity argument, (or a single argument as a string of a +form: `'enderchest_steve'` for legacy support). If your player name starts with `'enderchest_'`, first of all, tough luck, +but then it can be always accessed by passing a player entity value. If all else fails, it will try to identify first three arguments as coordinates of a block position of -a block inventory. Player inventories can also be called by their name. +a block inventory. Player inventories can also be called by their name. -You can also use `'equipment'` as a keyword preceeding an entity indicating the need of access that entity as a mob. -Equipment inventory -consists of its armour and hand items, and a few living entites can have both, their regular inventory, and their equipment inventory. For some -entities (players) their regular inventory already contains the equipment. For entity types that only have -their equipment inventory, the equipment is returned by default. +A few living entities can have both: their regular inventory, and their equipment inventory. +Player's regular inventory already contains the equipment, but you can access the equipment part as well, as well as +their enderchest separately. For entity types that only have +their equipment inventory, the equipment is returned by default (`null` type). + +If that's confusing see examples under `inventory_size` on how to access inventories. All other `inventory_...()` functions +use the same scheme. -
-inventory_size(player()) => 41  // items
-inventory_size('enderchest', player()) => 27 // equipment
-inventory_size('equipment', player()) => 6 // equipment
-
If the entity or a block doesn't have -an inventory, they typically do nothing and return null. +an inventory, all API functions 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)` @@ -98,14 +99,26 @@ item name that serves as a replacement after crafting is done. Currently it can ### `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 +have an inventory.
 inventory_size(player()) => 41
 inventory_size('enderchest', player()) => 27 // enderchest
 inventory_size('equipment', player()) => 6 // equipment
+inventory_size(null, player()) => 41  // default inventory for players
+
 inventory_size(x,y,z) => 27 // chest
 inventory_size(block(pos)) => 5 // hopper
+
+horse = spawn('horse', x, y, z);
+inventory_size(horse); => 2 // default horse inventory
+inventory_size('equipment', horse); => 6 // unused horse equipment inventory
+inventory_size(null, horse); => 2 // default horse
+
+creeper = spawn('creeper', x, y, z);
+inventory_size(creeper); => 6 // default creeper inventory is equipment since it has no other
+inventory_size('equipment', creeper); => 6 // unused horse equipment inventory
+inventory_size(null, creeper); => 6 // creeper default is its equipment
 
### `inventory_has_items(inventory)` diff --git a/src/main/java/carpet/script/utils/LivingInventory.java b/src/main/java/carpet/script/utils/EquipmentInventory.java similarity index 96% rename from src/main/java/carpet/script/utils/LivingInventory.java rename to src/main/java/carpet/script/utils/EquipmentInventory.java index caa43b35..723157c5 100644 --- a/src/main/java/carpet/script/utils/LivingInventory.java +++ b/src/main/java/carpet/script/utils/EquipmentInventory.java @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack; import java.util.Arrays; import java.util.List; -public class LivingInventory implements Inventory +public class EquipmentInventory implements Inventory { private static final List slotToSlot = Arrays.asList( EquipmentSlot.MAINHAND, @@ -18,7 +18,7 @@ public class LivingInventory implements Inventory ); LivingEntity mob; - public LivingInventory(LivingEntity mob) + public EquipmentInventory(LivingEntity mob) { this.mob = mob; } diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java index c8309bec..81560643 100644 --- a/src/main/java/carpet/script/value/NBTSerializableValue.java +++ b/src/main/java/carpet/script/value/NBTSerializableValue.java @@ -4,7 +4,7 @@ import carpet.fakes.InventoryBearerInterface; import carpet.script.CarpetContext; import carpet.script.LazyValue; import carpet.script.exception.InternalExpressionException; -import carpet.script.utils.LivingInventory; +import carpet.script.utils.EquipmentInventory; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.Block; @@ -175,47 +175,15 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa return inventory; } - 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) + Value v1 = params.get(offset).evalValue(c); + if (v1.isNull()) { - 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(); - else if (e instanceof InventoryBearerInterface) inv = ((InventoryBearerInterface)e).getCMInventory(); - else if (e instanceof LivingEntity) inv = new LivingInventory((MobEntity) e); - if (inv == null) - return null; - - 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 access inventory needs to be positioned in the world"); - inv = getInventoryAt(c.s.getWorld(), pos); - if (inv == null) - return null; - 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 = getInventoryAt(c.s.getWorld(), pos); - if (inv == null) - return null; - return new InventoryLocator(pos, pos, inv, offset + 1); + offset ++; + v1 = params.get(offset).evalValue(c); } else if (v1 instanceof StringValue) { @@ -227,34 +195,67 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa if (player == null) throw new InternalExpressionException("enderchest inventory requires player argument"); return new InventoryLocator(player, player.getBlockPos(), player.getEnderChestInventory(), offset + 2, true); } - else if (strVal.equals("equipment")) + if (strVal.equals("equipment")) { Value v2 = params.get(1 + offset).evalValue(c); - if (!(v2 instanceof EntityValue)) throw new InternalExpressionException("mob inventory requires a mob argument"); + if (!(v2 instanceof EntityValue)) throw new InternalExpressionException("Equipment inventory requires a living entity argument"); Entity e = ((EntityValue) v2).getEntity(); - if (!(e instanceof LivingEntity)) throw new InternalExpressionException("mob inventory requires a mob argument"); - return new InventoryLocator(e, e.getBlockPos(), new LivingInventory((LivingEntity) e), offset + 2, false); - } - else - { - boolean isEnder = strVal.startsWith("enderchest_"); - if (isEnder) strVal = strVal.substring(11); // len("enderchest_") - ServerPlayerEntity player = c.s.getMinecraftServer().getPlayerManager().getPlayer(strVal); - if (player == null) throw new InternalExpressionException("String description of an inventory should either denote a player or player's enderchest"); - return new InventoryLocator( - player, - player.getBlockPos(), - isEnder ? player.getEnderChestInventory() : player.inventory, - offset + 1, - isEnder - ); + if (!(e instanceof LivingEntity)) throw new InternalExpressionException("Equipment inventory requires a living entity argument"); + return new InventoryLocator(e, e.getBlockPos(), new EquipmentInventory((LivingEntity) e), offset + 2); } + boolean isEnder = strVal.startsWith("enderchest_"); + if (isEnder) strVal = strVal.substring(11); // len("enderchest_") + ServerPlayerEntity player = c.s.getMinecraftServer().getPlayerManager().getPlayer(strVal); + if (player == null) throw new InternalExpressionException("String description of an inventory should either denote a player or player's enderchest"); + return new InventoryLocator( + player, + player.getBlockPos(), + isEnder ? player.getEnderChestInventory() : player.inventory, + offset + 1, + isEnder + ); + } + if (v1 instanceof EntityValue) + { + Inventory inv = null; + 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(); + else if (e instanceof InventoryBearerInterface) inv = ((InventoryBearerInterface)e).getCMInventory(); + else if (e instanceof LivingEntity) return new InventoryLocator(e, e.getBlockPos(), new EquipmentInventory((MobEntity) e), offset+1); + if (inv == null) + return null; + + return new InventoryLocator(e, e.getBlockPos(), inv, offset+1); + } + if (v1 instanceof BlockValue) + { + BlockPos pos = ((BlockValue) v1).getPos(); + if (pos == null) + throw new InternalExpressionException("Block to access inventory needs to be positioned in the world"); + Inventory inv = getInventoryAt(c.s.getWorld(), pos); + if (inv == null) + return null; + return new InventoryLocator(pos, pos, inv, offset+1); + } + 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()); + Inventory inv = getInventoryAt(c.s.getWorld(), pos); + if (inv == null) + return null; + 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 = getInventoryAt(c.s.getWorld(), pos); + Inventory inv = getInventoryAt(c.s.getWorld(), pos); if (inv == null) return null; return new InventoryLocator(pos, pos, inv, offset + 3);