Skip to content

Commit

Permalink
Fix Network Changes on Payload Thread Handling (#156)
Browse files Browse the repository at this point in the history
Co-authored-by: Dennis C <xfacthd@gmx.de>
  • Loading branch information
ChampionAsh5357 and XFactHD committed Sep 8, 2024
1 parent 1f8e3b3 commit e8f8388
Showing 1 changed file with 68 additions and 12 deletions.
80 changes: 68 additions & 12 deletions docs/networking/payload.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ public static void register(final RegisterPayloadHandlersEvent event) {
MyData.TYPE,
MyData.STREAM_CODEC,
new DirectionalPayloadHandler<>(
ClientPayloadHandler::handleData,
ServerPayloadHandler::handleData
ClientPayloadHandler::handleDataOnMain,
ServerPayloadHandler::handleDataOnMain
)
);
}
Expand All @@ -79,7 +79,72 @@ Now that we have registered the payload we need to implement a handler. For this
```java
public class ClientPayloadHandler {

public static void handleData(final MyData data, final IPayloadContext context) {
public static void handleDataOnMain(final MyData data, final IPayloadContext context) {
// Do something with the data, on the main thread
blah(data.age());
}
}
```

Here a couple of things are of note:

- The handling method here gets the payload, and a contextual object.
- The handling method of the payload is, by default, invoked on the main thread.


If you need to do some computation that is resource intensive, then the work should be done on the network thread, instead of blocking the main thread. This is done by setting the `HandlerThread` of the `PayloadRegistrar` to `HandlerThread#NETWORK` via `PayloadRegistrar#executesOn` before registering the payload.

```java
@SubscribeEvent
public static void register(final RegisterPayloadHandlersEvent event) {
final PayloadRegistrar registrar = event.registrar("1")
.executesOn(HandlerThread.NETWORK); // All subsequent payloads will register on the network thread
registrar.playBidirectional(
MyData.TYPE,
MyData.STREAM_CODEC,
new DirectionalPayloadHandler<>(
ClientPayloadHandler::handleDataOnNetwork,
ServerPayloadHandler::handleDataOnNetwork
)
);
}
```

:::note
All payloads registered after an `executesOn` call will retain the same thread execution location until `executesOn` is called again.

```java
PayloadRegistrar registrar = event.registrar("1");

registrar.playBidirectional(...); // On the main thread
registrar.playBidirectional(...); // On the main thread

// Configuration methods modify the state of the registrar
// by creating a new instance, so the change needs to be
/// updated by storing the result
registrar = registrar.executesOn(HandlerThread.NETWORK);

registrar.playBidirectional(...); // On the network thread
registrar.playBidirectional(...); // On the network thread

registrar = registrar.executesOn(HandlerThread.MAIN);

registrar.playBidirectional(...); // On the main thread
registrar.playBidirectional(...); // On the main thread
```
:::

Here a couple of things are of note:

- If you want to run code on the main game thread you can use `enqueueWork` to submit a task to the main thread.
- The method will return a `CompletableFuture` that will be completed on the main thread.
- Notice: A `CompletableFuture` is returned, this means that you can chain multiple tasks together, and handle exceptions in a single place.
- If you do not handle the exception in the `CompletableFuture` then it will be swallowed, **and you will not be notified of it**.

```java
public class ClientPayloadHandler {

public static void handleDataOnNetwork(final MyData data, final IPayloadContext context) {
// Do something with the data, on the network thread
blah(data.name());

Expand All @@ -96,15 +161,6 @@ public class ClientPayloadHandler {
}
```

Here a couple of things are of note:

- The handling method here gets the payload, and a contextual object.
- The handler of the payload method is invoked on the networking thread, so it is important to do all the heavy work here, instead of blocking the main game thread.
- If you want to run code on the main game thread you can use `enqueueWork` to submit a task to the main thread.
- The method will return a `CompletableFuture` that will be completed on the main thread.
- Notice: A `CompletableFuture` is returned, this means that you can chain multiple tasks together, and handle exceptions in a single place.
- If you do not handle the exception in the `CompletableFuture` then it will be swallowed, **and you will not be notified of it**.

With your own payloads you can then use those to configure the client and server using [Configuration Tasks][configuration].

## Sending Payloads
Expand Down

0 comments on commit e8f8388

Please sign in to comment.