User Tools

Site Tools


zh_cn:tutorial:inventory

将物品放在容器中

阅读本教程之前,请确保您已将方块实体制作完成。

将物品存储在BlockEntity中的标准方法是使其成为Inventory。 这使得漏斗(或其他mods)无需任何额外的工作即可从您的BlockEntity放入和提取物品。

实现Inventory接口

Inventory只是一个接口,这意味着实际的ItemStack状态将需要存储在您的BlockEntity上。 可以使用DefaultedList <ItemStack>作为存储这些ItemStacks的简便方法, 因为可以将其默认设置为ItemStack.Empty,这是表示插槽中没有项目的正确方法。 实现Inventory非常简单,但乏味且容易出错, 因此,我们将使用它的默认实现,该实现只需要给它一个DefaultList <ItemStack>(将其复制为新文件):

ImplementedInventory.java
/**
 * A simple {@code Inventory} implementation with only default methods + an item list getter.
 *
 * Originally by Juuz
 */
public interface ImplementedInventory extends Inventory {
    /**
     * Gets the item list of this inventory.
     * Must return the same instance every time it's called.
     */
    DefaultedList<ItemStack> getItems();
    // Creation
    /**
     * Creates an inventory from the item list.
     */
    static ImplementedInventory of(DefaultedList<ItemStack> items) {
        return () -> items;
    }
    /**
     * Creates a new inventory with the size.
     */
    static ImplementedInventory ofSize(int size) {
        return of(DefaultedList.ofSize(size, ItemStack.EMPTY));
    }
    // Inventory
    /**
     * Returns the inventory size.
     */
    @Override
    default int getInvSize() {
        return getItems().size();
    }
    /**
     * @return true if this inventory has only empty stacks, false otherwise
     */
    @Override
    default boolean isInvEmpty() {
        for (int i = 0; i < getInvSize(); i++) {
            ItemStack stack = getInvStack(i);
            if (!stack.isEmpty()) {
                return false;
            }
        }
        return true;
    }
    /**
     * Gets the item in the slot.
     */
    @Override
    default ItemStack getInvStack(int slot) {
        return getItems().get(slot);
    }
    /**
     * Takes a stack of the size from the slot.
     * <p>(default implementation) If there are less items in the slot than what are requested,
     * takes all items in that slot.
     */
    @Override
    default ItemStack takeInvStack(int slot, int count) {
        ItemStack result = Inventories.splitStack(getItems(), slot, count);
        if (!result.isEmpty()) {
            markDirty();
        }
        return result;
    }
    /**
     * Removes the current stack in the {@code slot} and returns it.
     */
    @Override
    default ItemStack removeInvStack(int slot) {
        return Inventories.removeStack(getItems(), slot);
    }
    /**
     * Replaces the current stack in the {@code slot} with the provided stack.
     * <p>If the stack is too big for this inventory ({@link Inventory#getInvMaxStackAmount()}),
     * it gets resized to this inventory's maximum amount.
     */
    @Override
    default void setInvStack(int slot, ItemStack stack) {
        getItems().set(slot, stack);
        if (stack.getCount() > getInvMaxStackAmount()) {
            stack.setCount(getInvMaxStackAmount());
        }
    }
    /**
     * Clears {@linkplain #getItems() the item list}}.
     */
    @Override
    default void clear() {
        getItems().clear();
    }
    @Override
    default void markDirty() {
        // Override if you want behavior.
    }
    @Override
    default boolean canPlayerUseInv(PlayerEntity player) {
        return true;
    }
}

现在在您的BlockEntity中实施ImplementedInventory, 并为其提供存储该项目的DefaultedList <ItemStack>项目实例。 对于此示例,我们将在库存中最多存储2件物品:

public class DemoBlockEntity extends BlockEntity implements ImplementedInventory {
    private final DefaultedList<ItemStack> items = DefaultedList.ofSize(2, ItemStack.EMPTY);
 
    @Override
    public DefaultedList<ItemStack> getItems() {
        return items;
    }
    [...]
 
}

我们还需要保存容器以标记并从那里加载。 Inventories具有帮助方法,可以非常轻松地完成此任务:

public class DemoBlockEntity extends BlockEntity implements ImplementedInventory {
    [...]
    @Override
    public void fromTag(CompoundTag tag) {
        super.fromTag(tag);
        Inventories.fromTag(tag,items);
    }
 
    @Override
    public CompoundTag toTag(CompoundTag tag) {
        Inventories.toTag(tag,items);
        return super.toTag(tag);
    }
}

从容器(或任何容器)中提取和放入

在我们的块类中,我们将覆盖activate行为以从库存中放入和提取物品。 请注意,可以对任何实例执行此操作,而不仅仅是我们自己的(例如,您可以对箱子做相同的事情)。 首先,我们将处理放入内容物。 如果玩家拿着一个物品,他会放入他拿着的物品。 如果为空,它将进入第一个插槽;如果第一个为空,它将进入第二个插槽, 或者如果第二个也为空,我们将打印有关库存的一些信息。 请注意,将ItemStack放入内容物时,我们将其称为copy(),这样它就不会在玩家的ItemStack旁边被破坏。

public class ExampleBlock extends Block implements BlockEntityProvider {
    [...]
    @Override
    public boolean activate(BlockState blockState, World world, BlockPos blockPos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) {
        if (world.isClient) return true;
        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's hand there
            if (blockEntity.getInvStack(0).isEmpty()) {
                // Put the stack the player is holding into the inventory
                blockEntity.setInvStack(0, player.getStackInHand(hand).copy());
                // Remove the stack from the player's hand
                player.getStackInHand(hand).setCount(0);
            } else if (blockEntity.getInvStack(1).isEmpty()) {
                blockEntity.setInvStack(1, player.getStackInHand(hand).copy());
                player.getStackInHand(hand).setCount(0);
            } else {
                // If the inventory is full we'll print it's contents
                System.out.println("The first slot holds "
                        + blockEntity.getInvStack(0) + " and the second slot holds " + blockEntity.getInvStack(1));
            }
        } 
        return true;
    }
}

当玩家不持有物品时,我们将采取相反的行为。 我们将从第二个插槽中取出项目,然后第二个中的第一个为空。 如果第一个也是空的,我们将不做任何事情。

public class ExampleBlock extends Block implements BlockEntityProvider {
    [...]
    @Override
    public boolean activate(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.getInvStack(1).isEmpty()) {
                // Give the player the stack in the inventory
                player.inventory.offerOrDrop(world, blockEntity.getInvStack(1));
                // Remove the stack from the inventory
                blockEntity.removeInvStack(1);
            } else if (!blockEntity.getInvStack(0).isEmpty()) {
                player.inventory.offerOrDrop(world, blockEntity.getInvStack(0));
                blockEntity.removeInvStack(0);
            }
        }
 
        return true;
    }
}

实施补充内容物

如果您希望基于不同的方面(料斗或其他mod)与模块交互而具有不同的逻辑 您需要实施SidedInventory。 如果说您想这样做,那么您就不能从块的上方插入,您可以这样做:

public class DemoBlockEntity extends BlockEntity implements ImplementedInventory, SidedInventory {
    [...]
    @Override
    public int[] getInvAvailableSlots(Direction var1) {
        // Just return an array of all slots
        int[] result = new int[getItems().size()];
        for (int i = 0; i < result.length; i++) {
            result[i] = i;
        }
 
        return result;
    }
 
    @Override
    public boolean canInsertInvStack(int slot, ItemStack stack, Direction direction) {
        return direction != Direction.UP;
    }
 
    @Override
    public boolean canExtractInvStack(int slot, ItemStack stack, Direction direction) {
        return true;
    }
}
zh_cn/tutorial/inventory.txt · Last modified: 2019/12/19 05:37 by lightcolour