User Tools

Site Tools


tutorial:screenhandler

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tutorial:screenhandler [2020/08/14 17:25] manymoney2tutorial:screenhandler [2024/02/19 02:51] (current) – [ScreenHandler and Screen] transferSlot -> quickMove per yarn mappings netuserget
Line 1: Line 1:
-====== Creating a Container Block (DRAFT) (NEW) ====== +====== Creating a Container Block====== 
-In this tutorial we will create simple Storage Block similar to a dispenser. Explaining the ScreenHandler API from Fabric and Vanilla Minecraft along the way.+In this tutorial we will create simple storage block similar to a dispenser, explaining how to build a user interface with the ''ScreenHandler'' API from Fabric and Vanilla Minecraft along the way.
  
 Let us first explain some vocabulary: Let us first explain some vocabulary:
  
 **Screenhandler:** **Screenhandler:**
-A ScreenHandler is a class responsible for Synchronizing inventory contents between the Client and the Server. It can sync integer values like furnace progress aswell, which will be showed in the next Tutorial.+''ScreenHandler'' is a class responsible for synchronizing inventory contents between the client and the server. It can sync additional integer values like furnace progress as well, which will be showed in the next tutorial. 
 +Our subclass will have two constructors here: one will be used on the server side and will contain the real ''Inventory'' and another one will be used on the client side to hold the ''ItemStack''s and synchronize them.
  
 **Screen:** **Screen:**
-The Screen class only exists on the client and will render the background and other decorations for your ScreenHandler on the Screen+The ''Screen'' class only exists on the client and will render the background and other decorations for your ''ScreenHandler''.
  
-Tutorials based on this:  
- 
-- [[tutorial:extendedscreenhandler|Syncing Custom Data with Extended ScreenHandlers when screen is opened]] 
- 
-- [[tutorial:propertydelegates|Syncing Integers continuously with PropertyDelegates]] 
-===== Further Reading ===== 
-This and the following Tutorials are heavily inspired by the ScreenHandlerAPI ExampleMod. 
-It can be found here: [[https://github.com/FabricMC/fabric/tree/1.16/fabric-screen-handler-api-v1/src/testmod|ExampleMod on Github]] 
- 
-The documentation for the Fabric ScreenHandlerAPI can be found here: ##javadoc link here## 
 ===== Block and BlockEntity classes ===== ===== Block and BlockEntity classes =====
  
  
-First we need to create the Block and its BlockEntity+First we need to create the ''Block'' and its ''BlockEntity''.
  
 <code java [enable_line_numbers="true"] BoxBlock.java> <code java [enable_line_numbers="true"] BoxBlock.java>
Line 32: Line 23:
  
     @Override     @Override
-    public BlockEntity createBlockEntity(BlockView world) { +    public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { 
-        return new BoxBlockEntity();+        return new BoxBlockEntity(pos, state);
     }     }
  
Line 45: Line 36:
     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) {
-            //This will call the createScreenHandlerFactory method from blockWithEntity, which will return our blockEntity casted +            //This will call the createScreenHandlerFactory method from BlockWithEntity, which will return our blockEntity casted to 
-            //to a namedScreenHandlerFactory+            //a namedScreenHandlerFactory. If your block class does not extend BlockWithEntity, it needs to implement createScreenHandlerFactory.
             NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos);             NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos);
  
Line 79: Line 70:
     @Override     @Override
     public int getComparatorOutput(BlockState state, World world, BlockPos pos) {     public int getComparatorOutput(BlockState state, World world, BlockPos pos) {
-        return ScreenHandler.calculateComparatorOutput(world.getBlockEntity(pos))+        return ScreenHandler.calculateComparatorOutput(world.getBlockEntity(pos));
     }     }
 } }
 </code> </code>
  
-Now we will create our BlockEntity, it will use the ImplementedInventory Interface from the [[tutorial:inventory|Inventory Tutorial]]+Now we will create our ''BlockEntity'', it will use the ''ImplementedInventory'' interface from the [[tutorial:inventory|Inventory Tutorial]].
  
 <code java [enable_line_numbers="true"] BoxBlockEntity.java> <code java [enable_line_numbers="true"] BoxBlockEntity.java>
Line 90: Line 81:
     private final DefaultedList<ItemStack> inventory = DefaultedList.ofSize(9, ItemStack.EMPTY);     private final DefaultedList<ItemStack> inventory = DefaultedList.ofSize(9, ItemStack.EMPTY);
  
-    public BoxBlockEntity() { +    public BoxBlockEntity(BlockPos pos, BlockState state) { 
-        super(ExampleMod.BOX_BLOCK_ENTITY);+        super(ExampleMod.BOX_BLOCK_ENTITY, pos, state);
     }     }
  
Line 100: Line 91:
     public DefaultedList<ItemStack> getItems() {     public DefaultedList<ItemStack> getItems() {
         return inventory;         return inventory;
- 
     }     }
  
Line 116: Line 106:
     @Override     @Override
     public Text getDisplayName() {     public Text getDisplayName() {
-        return new TranslatableText(getCachedState().getBlock().getTranslationKey());+        // for 1.19+ 
 +        return Text.translatable(getCachedState().getBlock().getTranslationKey()); 
 +        // for earlier versions 
 +        // return new TranslatableText(getCachedState().getBlock().getTranslationKey());
     }     }
          
     @Override     @Override
-    public void fromTag(BlockState state, CompoundTag tag) { +    public void readNbt(NbtCompound nbt) { 
-        super.fromTag(state, tag); +        super.readNbt(nbt); 
-        inventory = DefaultedList.ofSize(invsize, ItemStack.EMPTY); +        Inventories.readNbt(nbt, this.inventory);
-        Inventories.fromTag(tag, this.inventory);+
     }     }
  
     @Override     @Override
-    public CompoundTag toTag(CompoundTag tag) { +    public NbtCompound writeNbt(NbtCompound nbt) { 
-        super.toTag(tag); +        super.writeNbt(nbt); 
-        Inventories.toTag(tag, this.inventory); +        Inventories.writeNbt(nbt, this.inventory); 
-        return tag;+        return nbt;
     }     }
 } }
Line 152: Line 144:
  
     static {     static {
-        BOX_BLOCK = Registry.register(Registry.BLOCK, BOX, new BoxBlock(FabricBlockSettings.copyOf(Blocks.CHEST))); +        BOX_BLOCK = Registry.register(Registries.BLOCK, BOX, new BoxBlock(FabricBlockSettings.copyOf(Blocks.CHEST))); 
-        BOX_BLOCK_ITEM = Registry.register(Registry.ITEM, BOX, new BlockItem(BOX_BLOCK, new Item.Settings().group(ItemGroup.MISC)));+        BOX_BLOCK_ITEM = Registry.register(Registries.ITEM, BOX, new BlockItem(BOX_BLOCK, new Item.Settings()));
  
         //The parameter of build at the very end is always null, do not worry about it         //The parameter of build at the very end is always null, do not worry about it
 +        // pre-1.17
         BOX_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, BOX, BlockEntityType.Builder.create(BoxBlockEntity::new, BOX_BLOCK).build(null));         BOX_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, BOX, BlockEntityType.Builder.create(BoxBlockEntity::new, BOX_BLOCK).build(null));
 +        // In 1.17 use FabricBlockEntityTypeBuilder instead of BlockEntityType.Builder
 +        BOX_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, BOX, FabricBlockEntityTypeBuilder.create(BoxBlockEntity::new, BOX_BLOCK).build(null));
     }     }
  
Line 170: Line 165:
 ===== ScreenHandler and Screen ===== ===== ScreenHandler and Screen =====
  
-We need a ScreenHandler Class and a HandledScreen Class to display and sync the GUI. ScreenHandler classes are used to synchronize GUI state between the server and the client. HandledScreen classes are fully client-sided and are responsible for drawing GUI elements.+As explained earlier, we need both ''ScreenHandler'' and a ''HandledScreen'' to display and sync the GUI. ''ScreenHandler'' classes are used to synchronize GUI state between the server and the client. ''HandledScreen'' classes are fully client-sided and are responsible for drawing GUI elements.
  
 <code java [enable_line_numbers="true"] BoxScreenHandler.java> <code java [enable_line_numbers="true"] BoxScreenHandler.java>
Line 178: Line 173:
     //This constructor gets called on the client when the server wants it to open the screenHandler,     //This constructor gets called on the client when the server wants it to open the screenHandler,
     //The client will call the other constructor with an empty Inventory and the screenHandler will automatically     //The client will call the other constructor with an empty Inventory and the screenHandler will automatically
-    //sync this empty inventory with the inventory on the server+    //sync this empty inventory with the inventory on the server.
     public BoxScreenHandler(int syncId, PlayerInventory playerInventory) {     public BoxScreenHandler(int syncId, PlayerInventory playerInventory) {
         this(syncId, playerInventory, new SimpleInventory(9));         this(syncId, playerInventory, new SimpleInventory(9));
Line 184: Line 179:
  
     //This constructor gets called from the BlockEntity on the server without calling the other constructor first, the server knows the inventory of the container     //This constructor gets called from the BlockEntity on the server without calling the other constructor first, the server knows the inventory of the container
-    //and can therefore directly provide it as an argument. This inventory will then be synced to the Client+    //and can therefore directly provide it as an argument. This inventory will then be synced to the client.
     public BoxScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) {     public BoxScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) {
         super(ExampleMod.BOX_SCREEN_HANDLER, syncId);         super(ExampleMod.BOX_SCREEN_HANDLER, syncId);
Line 222: Line 217:
     // Shift + Player Inv Slot     // Shift + Player Inv Slot
     @Override     @Override
-    public ItemStack transferSlot(PlayerEntity player, int invSlot) {+    public ItemStack quickMove(PlayerEntity player, int invSlot) {
         ItemStack newStack = ItemStack.EMPTY;         ItemStack newStack = ItemStack.EMPTY;
         Slot slot = this.slots.get(invSlot);         Slot slot = this.slots.get(invSlot);
Line 250: Line 245:
  
 <code java [enable_line_numbers="true"] BoxScreen.java> <code java [enable_line_numbers="true"] BoxScreen.java>
-public class BoxScreen extends HandledScreen<ScreenHandler> {+public class BoxScreen extends HandledScreen<BoxScreenHandler> {
     //A path to the gui texture. In this example we use the texture from the dispenser     //A path to the gui texture. In this example we use the texture from the dispenser
     private static final Identifier TEXTURE = new Identifier("minecraft", "textures/gui/container/dispenser.png");     private static final Identifier TEXTURE = new Identifier("minecraft", "textures/gui/container/dispenser.png");
  
-    public BoxScreen(ScreenHandler handler, PlayerInventory inventory, Text title) {+    public BoxScreen(BoxScreenHandler handler, PlayerInventory inventory, Text title) {
         super(handler, inventory, title);         super(handler, inventory, title);
     }     }
Line 260: Line 255:
     @Override     @Override
     protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) {     protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) {
-        RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); +        RenderSystem.setShader(GameRenderer::getPositionTexProgram); 
-        client.getTextureManager().bindTexture(TEXTURE);+        RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); 
 +        RenderSystem.setShaderTexture(0, TEXTURE);
         int x = (width - backgroundWidth) / 2;         int x = (width - backgroundWidth) / 2;
         int y = (height - backgroundHeight) / 2;         int y = (height - backgroundHeight) / 2;
         drawTexture(matrices, x, y, 0, 0, backgroundWidth, backgroundHeight);         drawTexture(matrices, x, y, 0, 0, backgroundWidth, backgroundHeight);
 +        //in 1.20 or above,this method is in DrawContext class.
     }     }
  
Line 286: Line 283:
  
  
-As Screens are are client only concept, we can only register them on the client+As screens are client-only concept, we can only register them on the client.
  
-<code java [enable_line_numbers="true"BiggerChestBlock.java>+<code java [enable_line_numbers="true"ExampleModClient.java>
  
 @Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
Line 294: Line 291:
     @Override     @Override
     public void onInitializeClient() {     public void onInitializeClient() {
-        ScreenRegistry.register(ExampleMod.BOX_SCREEN_HANDLER, BoxScreen::new);+        HandledScreens.register(ExampleMod.BOX_SCREEN_HANDLER, BoxScreen::new);
     }     }
 } }
Line 300: Line 297:
 </code> </code>
  
-ScreenHandlers exist both on Client and on the Server and therefore have to be registered on Both+Don't forget to register this entrypoint in ''fabric.mod.json'' if you haven't done it yet: 
 +<code json> 
 +/* ... */ 
 +  "entrypoints":
 +    /* ... */ 
 +    "client":
 +      "tutorial.path.to.ExampleModClient" 
 +    ] 
 +  }, 
 +</code> 
 + 
 +''ScreenHandler''exist both on the client and on the server and therefore have to be registered on both.
  
 <code java [enable_line_numbers="true"] ExampleMod.java> <code java [enable_line_numbers="true"] ExampleMod.java>
Line 326: Line 334:
  
 {{:tutorial:bildschirmfoto_vom_2020-08-14_18-32-07.png?nolink&400|}} {{:tutorial:bildschirmfoto_vom_2020-08-14_18-32-07.png?nolink&400|}}
 +
 +===== Further Reading =====
 +- [[tutorial:extendedscreenhandler|Syncing Custom Data with Extended ScreenHandlers when screen is opened]]
 +
 +- [[tutorial:propertydelegates|Syncing Integers continuously with PropertyDelegates]]
 +
 +- An example mod using the ''ScreenHandler'' API: [[https://github.com/FabricMC/fabric/tree/1.16/fabric-screen-handler-api-v1/src/testmod|ExampleMod on Github]].
  
tutorial/screenhandler.1597425935.txt.gz · Last modified: 2020/08/14 17:25 by manymoney2