User Tools

Site Tools


tutorial:extendedscreenhandler

This is an old revision of the document!


Syncing Custom Data with Extended ScreenHandlers

In this tutorial we will use the ExtendedScreenHandler to transfer arbitary data from the Server to the Client ScreenHandler when the ScreenHandler is opened.

In our example we will send the position of the block and render it as the containers title

To understand this tutorial you need to read the first Screenhandler tutorial. Methods which have no code here were already shown in that tutorial

BlockEntity

As the Block class does not need to be changed at all we leave it out here.

Our blockEntity now implements ExtendedScreenHandlerFactory, this interfaces provides us the writeScreenOpeningData method, which will be called on the server when it requests the client to open a screenHandler. The data you write into the PacketByteBuf will be transfered to the client over the network.

BoxBlockEntity.java
  1. public class BoxBlockEntity extends BlockEntity implements ExtendedScreenHandlerFactory, ImplementedInventory {
  2. private final DefaultedList<ItemStack> inventory = DefaultedList.ofSize(9, ItemStack.EMPTY);
  3.  
  4. public BoxBlockEntity() {
  5. super(Test.BOX_BLOCK_ENTITY);
  6. }
  7.  
  8.  
  9. //From the ImplementedInventory Interface
  10.  
  11. @Override
  12. public DefaultedList<ItemStack> getItems() {
  13. return inventory;
  14.  
  15. }
  16.  
  17. //These Methods are from the NamedScreenHandlerFactory Interface
  18.  
  19. @Override
  20. public @Nullable ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) {
  21. //We provide this to the screenHandler as our class Implements Inventory
  22. //Only the Server has the Inventory at the start, this will be synced to the client in the ScreenHandler
  23. return new BoxScreenHandler(syncId, playerInventory, this);
  24. }
  25.  
  26. @Override
  27. public Text getDisplayName() {
  28. return new TranslatableText(getCachedState().getBlock().getTranslationKey());
  29. }
  30.  
  31. //This Method is from the ExtendedScreenHandlerFactory
  32.  
  33. //This method gets called on the Server when it requests the client to open the screenHandler.
  34. //The contents you write into the packetByteBuf will automatically be transferred in a packet to the client
  35. //and the ScreenHandler Constructor with the packetByteBuf argument gets called on the client
  36. //
  37. //The order you insert things here is the same as you need to extract them. You do not need to reverse the order!
  38. @Override
  39. public void writeScreenOpeningData(ServerPlayerEntity serverPlayerEntity, PacketByteBuf packetByteBuf) {
  40. //The pos field is a public field from BlockEntity
  41. packetByteBuf.writeBlockPos(pos);
  42. }
  43. }

Our new ExtendedScreenHandler

BoxScreenHandler.java
  1. public class BoxScreenHandler extends ScreenHandler {
  2. //We save the blockPos we got from the Server and provide a getter for it so the BoxScreen can read that information
  3. private BlockPos pos;
  4. private final Inventory inventory;
  5.  
  6. //This constructor gets called on the client when the server wants it to open the screenHandler,
  7. //The client will call the super constructor with an empty Inventory and the screenHandler will automatically
  8. //sync this empty inventory with the inventory on the server
  9.  
  10. //NEW: The constructor of the client now gets the PacketByteBuf we filled in the BlockEntity
  11. public BoxScreenHandler(int syncId, PlayerInventory playerInventory, PacketByteBuf buf) {
  12. this(syncId, playerInventory, new SimpleInventory(9));
  13. pos = buf.readBlockPos();
  14. }
  15.  
  16. //This constructor gets called from the BlockEntity on the server, the server knows the inventory of the container
  17. //and can therefore directly provide it as an argument. This inventory will then be synced to the Client
  18. public BoxScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) {
  19. //[...]
  20. // See first Screenhandler Tutorial for the rest of the code
  21.  
  22. //Why do we use BlockPos.ORIGIN here?
  23. //This is because the packetByteBuf with our blockPosition is only availible on the Client, so we need a placeholder
  24. //value here. This is not a problem however, as the Server version of the ScreenHandler does not really need this
  25. //information.
  26. pos = BlockPos.ORIGIN;
  27.  
  28. [...]
  29. }
  30.  
  31. //this getter will be used by our Screen class
  32. public BlockPos getPos() {
  33. return pos;
  34. }
  35.  
  36. @Override
  37. public boolean canUse(PlayerEntity player) {
  38. return this.inventory.canPlayerUse(player);
  39. }
  40.  
  41. // See Screenhandler Tutorial
  42. // Shift + Player Inv Slot
  43. @Override
  44. public ItemStack transferSlot(PlayerEntity player, int invSlot);
  45. }

Using the Information of the ExtendedScreenHandler in our Screen

BoxScreen.java
  1. public class BoxScreen extends HandledScreen<ScreenHandler> {
  2. private static final Identifier TEXTURE = new Identifier("minecraft", "textures/gui/container/dispenser.png");
  3.  
  4. public BoxScreen(ScreenHandler handler, PlayerInventory inventory, Text title) {
  5. super(handler, inventory, getPositionText(handler).orElse(title));
  6. //We try to get the block position to use it as our title, if that fails for some reason we will use the default title
  7. }
  8.  
  9. //This method will try to get the Position from the ScreenHandler, as ScreenRendering only happens on the client we
  10. //get the ScreenHandler instance here which has the correct BlockPos in it!
  11. private static Optional<Text> getPositionText(ScreenHandler handler) {
  12. if (handler instanceof BoxScreenHandler) {
  13. BlockPos pos = ((BoxScreenHandler) handler).getPos();
  14. return pos != null ? Optional.of(new LiteralText("(" + pos.toShortString() + ")")) : Optional.empty();
  15. } else {
  16. return Optional.empty();
  17. }
  18. }
  19.  
  20.  
  21. @Override
  22. protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) { [...] }
  23.  
  24. @Override
  25. public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { [...] }
  26.  
  27. @Override
  28. protected void init() { [...] }
  29. }

Registering our ScreenHandler

ExampleMod.java
  1. public class ExampleMod implements ModInitializer {
  2.  
  3. [...]
  4. public static final ScreenHandlerType<BoxScreenHandler> BOX_SCREEN_HANDLER;
  5.  
  6. static {
  7. [...]
  8.  
  9. //we now use registerExtended as our screenHandler now accepts a packetByteBuf in its Constructor
  10. BOX_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(BOX, BoxScreenHandler::new);
  11. }
  12.  
  13. @Override
  14. public void onInitialize() {
  15.  
  16. }
  17. }
tutorial/extendedscreenhandler.1597422494.txt.gz · Last modified: 2020/08/14 16:28 by manymoney2