tutorial:inventory
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
tutorial:inventory [2019/08/05 14:02] – created fudge | tutorial:inventory [2023/11/06 23:28] (current) – binaris00 | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Storing items in a block as an Inventory ====== | ====== Storing items in a block as an Inventory ====== | ||
+ | Make sure you've [[tutorial: | ||
+ | |||
The standard way to store items in a BlockEntity is to make it an '' | The standard way to store items in a BlockEntity is to make it an '' | ||
This allows hoppers (or other mods) to insert and extract items from your BlockEntity without any extra work. | This allows hoppers (or other mods) to insert and extract items from your BlockEntity without any extra work. | ||
Line 15: | Line 17: | ||
*/ | */ | ||
public interface ImplementedInventory extends Inventory { | public interface ImplementedInventory extends Inventory { | ||
+ | |||
/** | /** | ||
- | | + | |
* Must return the same instance every time it's called. | * Must return the same instance every time it's called. | ||
*/ | */ | ||
DefaultedList< | DefaultedList< | ||
- | | + | |
/** | /** | ||
* Creates an inventory from the item list. | * Creates an inventory from the item list. | ||
Line 27: | Line 30: | ||
return () -> items; | return () -> items; | ||
} | } | ||
+ | | ||
/** | /** | ||
- | * Creates a new inventory with the size. | + | * Creates a new inventory with the specified |
*/ | */ | ||
static ImplementedInventory ofSize(int size) { | static ImplementedInventory ofSize(int size) { | ||
return of(DefaultedList.ofSize(size, | return of(DefaultedList.ofSize(size, | ||
} | } | ||
- | | + | |
/** | /** | ||
* Returns the inventory size. | * Returns the inventory size. | ||
*/ | */ | ||
@Override | @Override | ||
- | default int getInvSize() { | + | default int size() { |
return getItems().size(); | return getItems().size(); | ||
} | } | ||
+ | | ||
/** | /** | ||
- | * @return true if this inventory has only empty stacks, false otherwise | + | * Checks if the inventory is empty. |
+ | * @return true if this inventory has only empty stacks, false otherwise. | ||
*/ | */ | ||
@Override | @Override | ||
- | default boolean | + | default boolean |
- | for (int i = 0; i < getInvSize(); i++) { | + | for (int i = 0; i < size(); i++) { |
- | ItemStack stack = getInvStack(i); | + | ItemStack stack = getStack(i); |
if (!stack.isEmpty()) { | if (!stack.isEmpty()) { | ||
return false; | return false; | ||
Line 54: | Line 60: | ||
return true; | return true; | ||
} | } | ||
+ | | ||
/** | /** | ||
- | | + | |
*/ | */ | ||
@Override | @Override | ||
- | default ItemStack | + | default ItemStack |
return getItems().get(slot); | return getItems().get(slot); | ||
} | } | ||
+ | | ||
/** | /** | ||
- | | + | |
- | | + | |
- | * takes all items in that slot. | + | * @param count How many items to remove. |
+ | | ||
*/ | */ | ||
@Override | @Override | ||
- | default ItemStack | + | default ItemStack |
ItemStack result = Inventories.splitStack(getItems(), | ItemStack result = Inventories.splitStack(getItems(), | ||
if (!result.isEmpty()) { | if (!result.isEmpty()) { | ||
Line 74: | Line 83: | ||
return result; | return result; | ||
} | } | ||
+ | | ||
/** | /** | ||
- | * Removes | + | * Removes |
+ | | ||
*/ | */ | ||
@Override | @Override | ||
- | default ItemStack | + | default ItemStack |
return Inventories.removeStack(getItems(), | return Inventories.removeStack(getItems(), | ||
} | } | ||
+ | | ||
/** | /** | ||
- | * Replaces the current stack in the {@code | + | * Replaces the current stack in an inventory |
- | | + | |
- | * it gets resized to this inventory' | + | * @param stack The replacing itemstack. |
+ | | ||
+ | | ||
*/ | */ | ||
@Override | @Override | ||
- | default void setInvStack(int slot, ItemStack stack) { | + | default void setStack(int slot, ItemStack stack) { |
getItems().set(slot, | getItems().set(slot, | ||
- | if (stack.getCount() > getInvMaxStackAmount()) { | + | if (stack.getCount() > stack.getMaxCount()) { |
- | stack.setCount(getInvMaxStackAmount()); | + | stack.setCount(stack.getMaxCount()); |
} | } | ||
} | } | ||
+ | | ||
/** | /** | ||
- | * Clears | + | * Clears the inventory. |
*/ | */ | ||
@Override | @Override | ||
Line 100: | Line 115: | ||
getItems().clear(); | getItems().clear(); | ||
} | } | ||
+ | | ||
+ | /** | ||
+ | * Marks the state as dirty. | ||
+ | * Must be called after changes in the inventory, so that the game can properly save | ||
+ | * the inventory contents and notify neighboring blocks of inventory changes. | ||
+ | | ||
@Override | @Override | ||
default void markDirty() { | default void markDirty() { | ||
// Override if you want behavior. | // Override if you want behavior. | ||
} | } | ||
+ | | ||
+ | /** | ||
+ | * @return true if the player can use the inventory, false otherwise. | ||
+ | | ||
@Override | @Override | ||
- | default boolean | + | default boolean |
return true; | return true; | ||
} | } | ||
} | } | ||
</ | </ | ||
+ | |||
Now in your '' | Now in your '' | ||
and provide it with an instance of '' | and provide it with an instance of '' | ||
Line 121: | Line 147: | ||
return items; | return items; | ||
} | } | ||
- | ... | + | |
} | } | ||
</ | </ | ||
- | |||
We're also gonna need to save the inventories to tag and load it from there. | We're also gonna need to save the inventories to tag and load it from there. | ||
'' | '' | ||
<code java> | <code java> | ||
public class DemoBlockEntity extends BlockEntity implements ImplementedInventory { | public class DemoBlockEntity extends BlockEntity implements ImplementedInventory { | ||
- | ... | + | |
@Override | @Override | ||
- | public void fromTag(CompoundTag tag) { | + | public void readNbt(NbtCompound nbt) { |
- | super.fromTag(tag); | + | super.readNbt(nbt); |
- | Inventories.fromTag(tag,items); | + | Inventories.readNbt(nbt, items); |
} | } | ||
@Override | @Override | ||
- | public | + | public |
- | Inventories.toTag(tag,items); | + | Inventories.writeNbt(nbt, items); |
- | return super.toTag(tag); | + | return super.writeNbt(nbt); |
} | } | ||
} | } | ||
</ | </ | ||
- | ===== Extracting and inserting from your inventory ===== | + | ===== Extracting and inserting from your inventory |
- | Remember that the same thing can be done with any inventory... | + | In our block class, we'll override |
+ | Note that this can be done to any '' | ||
+ | First we'll handle inserting into the inventory. | ||
+ | It'll go into the first slot if it is empty, or to the second slot if the first one is empty, | ||
+ | or if the second is empty too we'll print some information about the inventory. | ||
+ | Note that we call '' | ||
+ | <code java> | ||
+ | public class ExampleBlock extends Block implements BlockEntityProvider { | ||
+ | [...] | ||
+ | @Override | ||
+ | public ActionResult onUse(BlockState blockState, World world, BlockPos blockPos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { | ||
+ | if (world.isClient) return ActionResult.SUCCESS; | ||
+ | Inventory blockEntity = (Inventory) world.getBlockEntity(blockPos); | ||
+ | |||
+ | |||
+ | if (!player.getStackInHand(hand).isEmpty()) { | ||
+ | // Check what is the first open slot and put an item from the player' | ||
+ | if (blockEntity.getStack(0).isEmpty()) { | ||
+ | // Put the stack the player is holding into the inventory | ||
+ | blockEntity.setStack(0, | ||
+ | // Remove the stack from the player' | ||
+ | player.getStackInHand(hand).setCount(0); | ||
+ | } else if (blockEntity.getStack(1).isEmpty()) { | ||
+ | blockEntity.setStack(1, | ||
+ | player.getStackInHand(hand).setCount(0); | ||
+ | } else { | ||
+ | // If the inventory is full we'll print it's contents | ||
+ | System.out.println(" | ||
+ | + blockEntity.getStack(0) + " and the second slot holds " + blockEntity.getStack(1)); | ||
+ | } | ||
+ | } | ||
+ | return ActionResult.SUCCESS; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | We'll have the opposite behavior when the player is not holding an item. We'll take the item from the second slot, and then the first one of the second is empty. | ||
+ | If the first is empty as well we won't do anything. | ||
+ | <code java> | ||
+ | public class ExampleBlock extends Block implements BlockEntityProvider { | ||
+ | [...] | ||
+ | @Override | ||
+ | public ActionResult onUse(BlockState blockState, World world, BlockPos blockPos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { | ||
+ | ... | ||
+ | if (!player.getStackInHand(hand).isEmpty()) { | ||
+ | ... | ||
+ | } else { | ||
+ | // If the player is not holding anything we'll get give him the items in the block entity one by one | ||
+ | |||
+ | // Find the first slot that has an item and give it to the player | ||
+ | if (!blockEntity.getStack(1).isEmpty()) { | ||
+ | // Give the player the stack in the inventory | ||
+ | player.getInventory().offerOrDrop(blockEntity.getStack(1)); | ||
+ | // Remove the stack from the inventory | ||
+ | blockEntity.removeStack(1); | ||
+ | } else if (!blockEntity.getStack(0).isEmpty()) { | ||
+ | player.getInventory().offerOrDrop(blockEntity.getStack(0)); | ||
+ | blockEntity.removeStack(0); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return ActionResult.SUCCESS; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Implementing SidedInventory ===== | ||
+ | If you want to have different logic based on what side things (hopper or other mods) interact with your block | ||
+ | you need to implement '' | ||
+ | If say you wanted to make it so you cannot insert from the upper side of the block, you would do this: | ||
+ | <code java> | ||
+ | public class DemoBlockEntity extends BlockEntity implements ImplementedInventory, | ||
+ | [...] | ||
+ | @Override | ||
+ | public int[] getInvAvailableSlots(Direction side) { | ||
+ | // Just return an array of all slots | ||
+ | int[] result = new int[getItems().size()]; | ||
+ | for (int i = 0; i < result.length; | ||
+ | result[i] = i; | ||
+ | } | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public boolean canInsert(int slot, ItemStack stack, Direction direction) { | ||
+ | return direction != Direction.UP; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public boolean canExtract(int slot, ItemStack stack, Direction direction) { | ||
+ | return true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </ |
tutorial/inventory.1565013743.txt.gz · Last modified: 2019/08/05 14:02 by fudge