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);