tutorial:containers
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revisionNext revisionBoth sides next revision | ||
tutorial:containers [2020/02/27 13:31] – new tutorial mkpoli | tutorial:containers [2020/08/14 07:03] – screen handlers part 2, needs extra testing leocth2 | ||
---|---|---|---|
Line 3: | Line 3: | ||
==== Block and BlockItem ==== | ==== Block and BlockItem ==== | ||
- | First create and register | + | First we need to create |
- | <code java [enable_line_numbers=" | + | <code java [enable_line_numbers=" |
public class BiggerChestBlock extends BlockWithEntity { | public class BiggerChestBlock extends BlockWithEntity { | ||
public BiggerChestBlock(Settings settings) { | public BiggerChestBlock(Settings settings) { | ||
super(settings); | super(settings); | ||
} | } | ||
- | + | | |
- | // We need to explicitly return a MODEL render type because BlockWithEntity has a side-effect of not showing | + | // A side effect of extending BlockWithEntity is it changes |
- | | + | |
public BlockRenderType getRenderType(BlockState state) { | public BlockRenderType getRenderType(BlockState state) { | ||
return BlockRenderType.MODEL; | return BlockRenderType.MODEL; | ||
Line 18: | Line 18: | ||
// We will create the BlockEntity later. | // We will create the BlockEntity later. | ||
+ | @Override | ||
public BlockEntity createBlockEntity(BlockView view) { | public BlockEntity createBlockEntity(BlockView view) { | ||
return new BiggerChestBlockEntity(); | return new BiggerChestBlockEntity(); | ||
} | } | ||
+ | @Override | ||
public void onPlaced(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) { | public void onPlaced(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) { | ||
if (itemStack.hasCustomName()) { | if (itemStack.hasCustomName()) { | ||
Line 31: | Line 33: | ||
} | } | ||
+ | @Override | ||
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { | public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { | ||
if (!world.isClient) { | if (!world.isClient) { | ||
Line 42: | Line 45: | ||
// Scatter the items in the chest when it is removed. | // Scatter the items in the chest when it is removed. | ||
+ | @Override | ||
public void onBlockRemoved(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { | public void onBlockRemoved(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { | ||
if (state.getBlock() != newState.getBlock()) { | if (state.getBlock() != newState.getBlock()) { | ||
Line 47: | Line 51: | ||
if (blockEntity instanceof BiggerChestBlockEntity) { | if (blockEntity instanceof BiggerChestBlockEntity) { | ||
ItemScatterer.spawn(world, | ItemScatterer.spawn(world, | ||
+ | // update comparators | ||
world.updateHorizontalAdjacent(pos, | world.updateHorizontalAdjacent(pos, | ||
} | } | ||
Line 53: | Line 58: | ||
} | } | ||
+ | @Override | ||
public boolean hasComparatorOutput(BlockState state) { | public boolean hasComparatorOutput(BlockState state) { | ||
return true; | return true; | ||
} | } | ||
+ | @Override | ||
public int getComparatorOutput(BlockState state, World world, BlockPos pos) { | public int getComparatorOutput(BlockState state, World world, BlockPos pos) { | ||
return Container.calculateComparatorOutput(world.getBlockEntity(pos)); | return Container.calculateComparatorOutput(world.getBlockEntity(pos)); | ||
Line 65: | Line 72: | ||
Then we need to register our Block and BlockItem. | Then we need to register our Block and BlockItem. | ||
- | <code java [enable_line_numbers=" | + | <code java [enable_line_numbers=" |
public class ExampleMod implements ModInitializer | public class ExampleMod implements ModInitializer | ||
{ | { | ||
Line 84: | Line 91: | ||
} | } | ||
</ | </ | ||
+ | |||
+ | You may refer to other tutorials to modify the appearance and other properties of the Block by adding models or adjusting rendering later. | ||
==== BlockEntity ==== | ==== BlockEntity ==== | ||
- | We then need to add an '' | + | BlockEntity is used for managing container inventories. Actually, it implements Inventory interface. It is required |
- | <code java> | + | < |
- | | + | public class BiggerChestBlockEntity extends LootableContainerBlockEntity { |
+ | | ||
+ | private static final int INVENTORY_SIZE = 54; // 9 * 6 = 54 | ||
+ | |||
+ | public BiggerChestBlockEntity() { | ||
+ | super(ExampleMod.BIGGER_CHEST_ENTITY_TYPE); | ||
+ | this.inventory = DefaultedList.ofSize(INVENTORY_SIZE, | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | protected Text getContainerName() { | ||
+ | return new TranslatableText(" | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | protected Container createMenu(int syncId, PlayerInventory playerInventory, | ||
+ | return new BiggerChestContainer(syncId, | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | protected DefaultedList< | ||
+ | return this.inventory; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | protected void setInvStackList(DefaultedList< | ||
+ | this.inventory = list; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public int getInvSize() { | ||
+ | return INVENTORY_SIZE; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void fromTag(CompoundTag tag) { | ||
+ | super.fromTag(tag); | ||
+ | this.inventory = DefaultedList.ofSize(this.getInvSize(), | ||
+ | if (!this.deserializeLootTable(tag)) { | ||
+ | Inventories.fromTag(tag, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public CompoundTag toTag(CompoundTag tag) { | ||
+ | super.toTag(tag); | ||
+ | if (!this.serializeLootTable(tag)) { | ||
+ | Inventories.toTag(tag, | ||
+ | } | ||
+ | return tag; | ||
+ | } | ||
+ | } | ||
</ | </ | ||
==== Container GUI and Screen ==== | ==== Container GUI and Screen ==== | ||
- | We need a Container | + | We need a ScreenHandler |
- | <code java [enable_line_numbers=" | + | <code java [enable_line_numbers=" |
- | public class BiggerChestContainer | + | public class BiggerChestScreenHandler |
private final Inventory inventory; // Chest inventory | private final Inventory inventory; // Chest inventory | ||
private static final int INVENTORY_SIZE = 54; // 6 rows * 9 cols | private static final int INVENTORY_SIZE = 54; // 6 rows * 9 cols | ||
- | protected | + | protected |
- | super(null, syncId); // Since we didn't create a ContainerType, we will place null here. | + | super(null, syncId); // Since we didn't create a ScreenHandlerType, we will place null here. |
this.inventory = inventory; | this.inventory = inventory; | ||
- | | + | |
- | inventory.onInvOpen(playerInventory.player); | + | inventory.onOpen(playerInventory.player); |
- | // Creating Slots for GUI. A Slot is essentially a correspoding | + | // Creating Slots for GUI. A Slot is essentially a corresponding |
int i; | int i; | ||
int j; | int j; | ||
Line 133: | Line 193: | ||
@Override | @Override | ||
public boolean canUse(PlayerEntity player) { | public boolean canUse(PlayerEntity player) { | ||
- | return this.inventory.canPlayerUseInv(player); | + | return this.inventory.canPlayerUse(player); |
} | } | ||
// Shift + Player Inv Slot | // Shift + Player Inv Slot | ||
+ | @Override | ||
public ItemStack transferSlot(PlayerEntity player, int invSlot) { | public ItemStack transferSlot(PlayerEntity player, int invSlot) { | ||
ItemStack newStack = ItemStack.EMPTY; | ItemStack newStack = ItemStack.EMPTY; | ||
Line 164: | Line 225: | ||
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | public class BiggerChestScreen extends | + | public class BiggerChestScreen extends |
// a path to gui texture, you may replace it with new Identifier(YourMod.MOD_ID, | // a path to gui texture, you may replace it with new Identifier(YourMod.MOD_ID, | ||
private static final Identifier TEXTURE = new Identifier(" | private static final Identifier TEXTURE = new Identifier(" | ||
- | public BiggerChestScreen(BiggerChestContainer container, PlayerInventory playerInventory, | + | public BiggerChestScreen(BiggerChestScreenHandler handler, PlayerInventory playerInventory, |
- | super(container, playerInventory, | + | super(handler, playerInventory, |
- | this.containerHeight | + | this.backgroundHeight |
} | } | ||
@Override | @Override | ||
- | protected void drawForeground(int mouseX, int mouseY) { | + | protected void drawForeground(MatrixStack matrices, |
- | this.font.draw(this.title.asFormattedString(), 8.0F, 6.0F, 4210752); | + | this.textRenderer.draw(matrices, |
- | this.font.draw(this.playerInventory.getDisplayName().asFormattedString(), 8.0F, (float)(this.containerHeight | + | this.textRenderer.draw(matrices, |
} | } | ||
Line 183: | Line 244: | ||
protected void drawBackground(float delta, int mouseX, int mouseY) { | protected void drawBackground(float delta, int mouseX, int mouseY) { | ||
RenderSystem.color4f(1.0F, | RenderSystem.color4f(1.0F, | ||
- | this.minecraft.getTextureManager().bindTexture(TEXTURE); | + | this.client.getTextureManager().bindTexture(TEXTURE); |
- | int i = (this.width - this.containerWidth) / 2; | + | int i = (this.width - this.backgroundWidth) / 2; |
- | int j = (this.height - this.containerHeight) / 2; | + | int j = (this.height - this.backgroundHeight) / 2; |
- | this.blit(i, | + | this.blit(i, |
- | this.blit(i, | + | this.blit(i, |
} | } | ||
} | } | ||
Line 198: | Line 259: | ||
public static final String BIGGER_CHEST_TRANSLATION_KEY = Util.createTranslationKey(" | public static final String BIGGER_CHEST_TRANSLATION_KEY = Util.createTranslationKey(" | ||
+ | @Override | ||
public void onInitialize() { | public void onInitialize() { | ||
[...] | [...] | ||
ContainerProviderRegistry.INSTANCE.registerFactory(BIGGER_CHEST, | ContainerProviderRegistry.INSTANCE.registerFactory(BIGGER_CHEST, | ||
- | final BlockEntity blockEntity | + | final World world = player.world; |
- | return((BiggerChestBlockEntity) blockEntity).createContainer(syncId, player.inventory); | + | final BlockPos pos = buf.readBlockPos(); |
+ | return | ||
}); | }); | ||
} | } | ||
Line 208: | Line 271: | ||
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
+ | @Override | ||
public void onInitializeClient() { | public void onInitializeClient() { | ||
[...] | [...] | ||
Line 214: | Line 278: | ||
</ | </ | ||
- | ==== Orgnizing | + | ==== Organizing |
- | After following | + | After all the steps, you should have your ExampleMod Class and ExampleClientMod Class as such: |
- | + | ||
- | You should have your ExampleMod Class and ExampleClientMod Class as such: | + | |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
Line 246: | Line 308: | ||
} | } | ||
</ | </ | ||
+ | |||
+ | {{tutorial: | ||
It's over and enjoy your custom container! | It's over and enjoy your custom container! |
tutorial/containers.txt · Last modified: 2022/05/27 15:57 by solidblock