Changes

1,086 bytes added ,  21:21, 28 August 2023
m
Line 36: Line 36:     
The last three parameters can be method references to either static or instance methods in Java. Remember that an instance method <code><nowiki>MSG.encode(FriendlyByteBuf)</nowiki></code> still satisfies <code><nowiki>BiConsumer<MSG, FriendlyByteBuf></nowiki></code>, the <code><nowiki>MSG</nowiki></code> simply becomes the implicit first argument.
 
The last three parameters can be method references to either static or instance methods in Java. Remember that an instance method <code><nowiki>MSG.encode(FriendlyByteBuf)</nowiki></code> still satisfies <code><nowiki>BiConsumer<MSG, FriendlyByteBuf></nowiki></code>, the <code><nowiki>MSG</nowiki></code> simply becomes the implicit first argument.
 +
 +
<syntaxhighlight lang="java">
 +
class MessagePacket {
 +
  public void encoder(FriendlyByteBuf buffer) {
 +
      // Write to buffer
 +
  }
 +
 +
  public static MessagePacket decoder(FriendlyByteBuf buffer) {
 +
      // Create packet from buffer data
 +
  }
 +
 +
  public void messageConsumer(Supplier<NetworkEvent.Context> ctx) {
 +
      // Handle message
 +
  }
 +
}
 +
 +
// Original direct registration syntax
 +
INSTANCE.registerMessage(id, MessagePacket.class,
 +
  MessagePacket::encoder,
 +
  MessagePacket::decoder,
 +
  MessagePacket::messageConsumer);
 +
  // Consumer here must use enqueueWork and setPacketHandled
 +
 +
// New builder-based definition
 +
INSTANCE.messageBuilder(MessagePacket.class, id)
 +
  .encoder(MessagePacket::encoder)
 +
  .decoder(MessagePacket::decoder)
 +
  .consumerMainThread(MessagePacket::messageConsumer)
 +
  .add();
 +
// You can use consumerMainThread or consumerNetworkThread.
 +
// If you use consumerMainThread, the builder will take care of the enqueueWork and setPacketHandled.
 +
// With consumerNetworkThread, you can return a value instead of calling setPacketHandled.
 +
</syntaxhighlight>
    
== Handling Packets ==
 
== Handling Packets ==
Line 72: Line 105:  
Note the presence of <code><nowiki>#setPacketHandled</nowiki></code>, which used to tell the network system that the packet has successfully completed handling.
 
Note the presence of <code><nowiki>#setPacketHandled</nowiki></code>, which used to tell the network system that the packet has successfully completed handling.
   −
{{Colored box|title=Alert|content=Packets are by default handled on the network thread.
+
=== Common Packet Handling Pitfalls ===
<br><br>
+
 
That means that your handler can _not_ interact with most game objects directly.
+
{{Colored box|title=Know that packets are by default handled on the network thread.|content=
 +
That means that your handler can ''not'' interact with most game objects directly.
 
Forge provides a convenient way to make your code execute on the main thread through the supplied <code><nowiki>NetworkEvent$Context</nowiki></code>.
 
Forge provides a convenient way to make your code execute on the main thread through the supplied <code><nowiki>NetworkEvent$Context</nowiki></code>.
 
Simply call <code><nowiki>NetworkEvent$Context#enqueueWork(Runnable)</nowiki></code>, which will call the given <code><nowiki>Runnable</nowiki></code> on the main thread at the next opportunity.}}
 
Simply call <code><nowiki>NetworkEvent$Context#enqueueWork(Runnable)</nowiki></code>, which will call the given <code><nowiki>Runnable</nowiki></code> on the main thread at the next opportunity.}}
   −
{{Colored box|title=Alert|content=Be defensive when handling packets on the server. A client could attempt to exploit the packet handling by sending unexpected data.
+
{{Colored box|title=Be defensive when handling packets on the server.|content=
<br><br>
+
A client could attempt to exploit the packet handling by sending unexpected data.
 +
<br>
 
A common problem is vulnerability to <code>arbitrary chunk generation</code>. This typically happens when the server is trusting a block position sent by a client to access blocks and block entities. When accessing blocks and block entities in unloaded areas of the level, the server will either generate or load this area from disk, then promply write it to disk. This can be exploited to cause <code>catastrophic damage</code> to a server's performance and storage space without leaving a trace.
 
A common problem is vulnerability to <code>arbitrary chunk generation</code>. This typically happens when the server is trusting a block position sent by a client to access blocks and block entities. When accessing blocks and block entities in unloaded areas of the level, the server will either generate or load this area from disk, then promply write it to disk. This can be exploited to cause <code>catastrophic damage</code> to a server's performance and storage space without leaving a trace.
 
<br>
 
<br>
 
To avoid this problem, a general rule of thumb is to only access blocks and block entities if <code><nowiki>Level#hasChunkAt</nowiki></code> is true.}}
 
To avoid this problem, a general rule of thumb is to only access blocks and block entities if <code><nowiki>Level#hasChunkAt</nowiki></code> is true.}}
   −
{{Colored box|title=Alert|content=Remember that DistExecutor runs on the '''physical side''', not the logical side.
+
{{Colored box|title=Register encoders on the physical client, as well as the physical server.|content=
<br><br>
   
If you only register an encoder for a clientbound packet on the physical server, your mod will likely crash or present unintended behaviour in single-player worlds. ''Forge will happily send packets that have no encoder defined, '''without a warning or error message!''''' They will be encoded as a 256-long byte buffer filled only with null bytes, by default.
 
If you only register an encoder for a clientbound packet on the physical server, your mod will likely crash or present unintended behaviour in single-player worlds. ''Forge will happily send packets that have no encoder defined, '''without a warning or error message!''''' They will be encoded as a 256-long byte buffer filled only with null bytes, by default.
 
<br>}}
 
<br>}}
25

edits