Sunday, 22 March 2020

Client<-->Server communication using your own custom messages (SimpleChannel) [1.14.4+]

Although vanilla uses ClientPlayNetHandler and ServerPlayNetHandler for sending packets, you should not use these when modding.  The SimpleChannel is provided for this purpose.

To skip straight to sample code, click here (example 60).

In many cases, you won’t need to create custom packets to keep your client and server code synchronised.  The vanilla code and Forge code do this in a number of ways already:
  • Creation, Removal, Movement, health, actions etc for Entities.  This is accomplished for new Entities by Forge packet EntitySpawnPacket.  You can define a custom handler for this using EntityRegistration.setCustomSpawning().
  • Removal or placement of Blocks
  • Adding DataWatcher variables to your Entity (see here)
  • Containers (Inventory, furnace, etc)
If none of these meet your needs and you need to send custom messages, there are three key components to know about:
  1. Your Message class which represents the message you want to send (for example - a client message to the server might indicate "launch a projectile at location [x,y,z]).  The Message must provides methods to
    * convert the member variables to a serialised format (PacketBuffer) for transmission, and
    * convert the PacketBuffer back to member variables on the receiving side
  2. A MessageHandler class, which is called on the receiving side when your Message arrives for processing
  3. SimpleChannel, which you use to define a channel for your communications as well as to register your Message and MessageHandler.
The Message and MessageHandler are closely coupled.  When registering them with SimpleNetworkWrapper, you need to provide a unique byte ID to identify the message type and its corresponding handler.

The generation, transmission, and receipt of a message (from Client to Server) is illustrated in the diagram below.  Sending a message from Server to Client follows the same pattern.

WARNING! The networking code is multithreaded and your MessageHandler needs to be very careful what it does to avoid crashing the game or introducing subtle, intermittent problems.  See here.

SimpleChannel also provides a number of methods you can use to send messages to the appropriate audience, for example

  • simpleChannel.send(PacketDistributor.PLAYER.with(playerMP), new MyMessage());  // Sending to one player
  • simpleChannel.send(PacketDistributor.TRACKING_CHUNK.with(chunk), new MyMessage()); // Send to all players tracking this chunk
  • simpleChannel.send(PacketDistributor.ALL.noArg(), new MyMessage()); // Sending to all connected players
  • etc

1 comment:

  1. Thanks for your the excellent job. There are not any other articles which could help reader understand the deep level of Minecraft better than yours.