diff --git a/content/news/20.4networking-rework.md b/content/news/20.4networking-rework.md index 451433c..2e0b39a 100644 --- a/content/news/20.4networking-rework.md +++ b/content/news/20.4networking-rework.md @@ -58,17 +58,13 @@ An example of the signature of the methods for the configuration phase is as fol ``` For the play phase, similar methods exist. For payloads that are supposed to be sent during both the play phase and the configuration phase, there also exists a pair. -However, here, the handler is a common supertype of the handling callbacks, and the handler only has a reduced common superset of the information available to both phase handlers to it available. +However, here, the handler is a common supertype of the handling callbacks, which has a reduced superset of the information available to the two different types. ### Payload discrimination When considering this system, you might, rightfully so, ask how the system keeps the different payload types apart from each other. -This is achieved by the system itself. It writes a discriminator ID to the connection before invoking the write method for a payload. -Conversely on the client side, the discriminator is read first, before a reader is looked up so that the rest of the payload can be read. +Similarly, on the client side, the discriminator is read first, then a reader is looked up so that the rest of the payload can be read. -{{< notice note >}} -The system handles reading and writing the discriminator itself, as a modder you do not need to take care of this yourself. -{{< /notice >}} The value of the discriminator during writing is retrieved from the `CustomPacketPayload#id()` method, and cannot be `null`. The value against which the id, read from the connection, is compared to find a reader, is the one that is given to the registrar as the first argument. @@ -79,7 +75,7 @@ We recommend that you store your ID in a `public static final ResourceLocation I {{< /notice >}} {{< notice warning >}} -Given that the id is used as a discriminator, it is important that you use a unique value, especially for the ResourceLocations path section for each payload type. If you try to register the same id twice, the registrar will throw an exception. If you try to register an id with a namespace other than the one the registrar is for, the registrar will throw an exception. You are free to request registrars for other namespaces than your own. +Given that the id is used as a discriminator, it is important that you use a unique value, especially for the path of each payload type. If you try to register the same id twice, the registrar will throw an exception. If you try to register an id with a namespace other than the one the registrar is for, the registrar will throw an exception. You are free to request registrars for other namespaces than your own. {{< /notice >}} ### Payload reading @@ -90,7 +86,7 @@ As we recommend that your payload implementations are `record`s in Java, instead {{< /notice >}} {{< notice warning >}} -There is no guarantee regarding which thread the reading callback is invoked upon. It is as such important to note that the method can be called on many threads in parallel if the same packet is received on many connections simultaneously. +There is no guarantee regarding which thread the reading or writing callback is invoked upon. It is as such important to note that the method can be called on many threads in parallel if the same packet is processed by many connections simultaneously. {{< /notice >}} ### Payload writing @@ -105,7 +101,7 @@ Payloads are only read and written if sent over a connection. This means that th {{< /notice >}} ### Payload handling -Once a payload has been written, transmitted and read, the payload handler is invoked. This handler is again looked up using the id of the payload, and then invoked with the context of the receiving end. Each payload handler takes two arguments the payload instance, and the context. +Once a payload has been written, transmitted and read, the payload handler is invoked. This handler is again looked up using the id of the payload, and then invoked with the context of the receiving end. Each handler takes two arguments the: payload instance, and the context. {{< notice warning >}} Payloads are processed on the network thread, and can as such happen in parallel with other payloads of the same type being handled. If you need to ensure that the payload is processed on the main thread, serially, see the `ISynchronizedWorkHandler` available in the context under the `workHandler()` method. @@ -115,7 +111,7 @@ Payloads are processed on the network thread, and can as such happen in parallel The context contains information, callbacks and entry points, to access the surrounding network system, the main thread, as well as handling processing other packets, or completing configuration tasks. ##### ReplyHandler -The reply handler can be used to quickly send a payload back to the sender. It is for example useful to send and answer to a query packet, or simply send an acknowledgment that you received and processed the payload. You still need to register the return payload. +The reply handler can be used to quickly send a payload back to the sender. It is, for example, useful to send and answer to a query packet, or to send an acknowledgment that you received and processed the payload. You still need to register the return payload. ##### PacketHandler In case you implement a packet splitting mechanism, whether that splits on full vanilla packets, or custom packet payloads, the `IPacketHandler` interface gives you access to the start of the processing pipeline, allowing you to process other payloads immediately. @@ -129,54 +125,52 @@ The packet handler also gives you access to a `disconnect(Component)` method, al ##### WorkHandler The work handler allows you to schedule work on the main thread of the receiving side. This might be the `Minecraft` class instance if the logical receiving side is the client, or the `MinecraftServer` instance if the receiving side is the server. -The system uses `CompleteableFuture` instances, so you can schedule different follow-up tasks, if need be. +The system uses `CompletableFuture` instances, so you are able to schedule different follow-up tasks. ##### PacketFlow -The context will indicate via the packet flow, what the receiving side currently is. If it is a server bound flow, then handler is currently being invoked in the context of the server. Is it a client bound flow, then the handler is currently being invoked in the context of the client. +The context will indicate, via the packet flow, what the receiving side currently is. If it is a serverbound flow, then the handler is currently being invoked in the context of the server. Is it a clientbound flow, then the handler is currently being invoked in the context of the client. ##### ConnectionProtocol -The current active connection protocol. Useful if you have raw bytes of a packet wrapped in your payload, allowing your handler to decode the inner packet or payload, before passing it to the `IPacketHandler` for processing. +The current active connection protocol is useful if you have raw bytes of a packet wrapped in your payload, allowing your handler to decode the inner packet or payload, before passing it to the `IPacketHandler` for processing. ##### ChannelHandlerContext -The netty channel handling context that is currently processing the network connection on which the payload was received. -This context can be used to retrieve the raw underlying connection via `ConnectionUtils` or again be used to process raw bytes of inner packets and payloads. +The Netty channel handling context that is currently processing the payload is also given as context. +This context can be used to retrieve the raw underlying connection via `ConnectionUtils`, or, be used to process raw bytes of inner packets and payloads. ##### Player -This is an `Optional` containing a player. +An `Optional` containing a player is also provided. If the handler is invoked on the server side, then this is the player that sent the payload. If the handler is invoked on the client side, then this is the local player, if it is available. ##### Level -This is an `Optional` containing the level the player is in. -If the handler is invoked on the server side, then this is the level the player is in. -If the handler is invoked on the client side, then this is the client's current level. +An `Optional` containing the level the player is in is provided too. ##### TaskCompletedHandler -This is a special contextual value only available to payloads for the configuration, which are specifically registered as such, to indicate that a specific configuration task has been completed, and that the next one can be started. +This is a special contextual value only available to payloads during the configuration phase, that indicates that a specific configuration task has been completed, and that the next one can be started. ##### Future additions to the contexts -We are fully aware that these entry points might not be all information you as a modder need to process a packet. In general, it is pretty easy to extend the interfaces and records. **They were specifically designed to allow for simple PRs in the future to add to them**, so please do not hesitate to create a quick PR to add your needed data to the context. +We are fully aware that these entry points might not be all information you, as a modder, need to process a packet. In general, it is pretty easy to extend the interfaces and records. **They were specifically designed to allow for simple PRs in the future to add to them**, so please do not hesitate to create a quick PR to add your needed data to the context. ### Packet Sending -In tandem with the refactoring of the channel registration mechanic we added new tools and systems to allow you to easier send a custom payload to different targets. +In tandem with the refactoring of the channel registration mechanic we added new tools and systems to allow you to more easily send a custom payload to different targets. #### PacketDistributor This wrapper class now has the ability to process custom payloads solely. Its instances and targets can be passed around since they are immutable. Several methods on extension classes will accept these, to facilitate easy transfer of payloads. #### Extension objects -We extended several vanilla types allowing for them to accept payloads as well, not just packets. Examples are chunk sections, listeners, entities and players. +We extended several vanilla types allowing them to accept payloads as well, not just packets. Examples are chunk sections, listeners, entities and players. ### Netty information -In contrast with the past, we now store a lot of information related to the connection, for example the negotiated payload types, on the connection object itself. To this accord we added several attributes to store this information in. Although the attributes are considered part of the internal API, if somebody wants to dig through the internal guts, they should feel free to do so, however there is no guarantee that we would change them around in future releases, even outside the BC window. +We store a lot of information related to the connection, for example the negotiated payload types, on the connection object itself. As such, we added several attributes to store this information in. These attributes are considered internal API, use them at your own risk. ## Configuration tasks on client join ### Tasks Vanilla now provides a centralized way to perform tasks and jobs that need to be performed when a player joins. The player won't be instantiated or added to a world until these tasks are completed. -Under normal circumstances these tasks are implementations of the `ConfigurationTask` interface, with a single method: `start(Consumer>)`. However, this is subpar in our situation. Modders should never really have to touch raw Packets to perform their duties, only payloads. And as such it was decided to have modders implement the `ICustomConfigurationTask` interface from NeoForge itself. This provides a wrapper around the `ConfigurationTask` signature and allows for sending payloads instead of packets, by implementing `run(Consumer)` instead. The given consumer will then automatically convert the payload to a packet and send it to the client that is being configured. +Under normal circumstances these tasks are implementations of the `ConfigurationTask` interface, with a single method: `start(Consumer>)`. However, this is subpar in our situation. Modders should never really have to touch raw Packets to perform their duties, only payloads. And as such it was decided to have modders implement the `ICustomConfigurationTask` interface from NeoForge. This provides a wrapper around the `ConfigurationTask` signature and allows sending payloads instead of packets, by implementing `run(Consumer)` instead. The given consumer will then automatically convert the payload to a packet and send it to the client that is being configured. {{< notice note >}} -In practice an instance of `ICustomConfigurationTask` is also an instance of `ConfigurationTask` as one extends the other. But to provide the ability for this to be a functional interface, the method `Start` is implemented as a default implementation. It is not recommended to also override that. +In practice, an instance of `ICustomConfigurationTask` is also an instance of `ConfigurationTask` as one extends the other. But to provide the ability for it to be a functional interface, the `start` method is implemented by default. You should not override it. {{< /notice >}} ### OnGameConfigurationEvent @@ -186,39 +180,38 @@ This event is fired to collect all tasks that should be run, and allows for the This event is fired on the mod bus, to preserve dependency order. Given that configuration tasks can only be running in order of registration, you can safely assume that configuration tasks of your dependencies have been running before yours. {{< /notice >}} -### Forge changes: +### NeoForge packet changes: Moved configuration sync, registry sync, and tier registry sync to configuration phase tasks. ## Bundle packet processing -In 1.20.2 Mojang introduced the bundling system for packets, which is a core component that allows for packets to be processed together. And started using sparsely. We anticipate modders want to use this system, so we adapted it to accept custom payloads. You will find a `sendBundled(CustomPacketPayload[] payloads)` method on the `ServerGamePacketListener` +In 1.19.4 Mojang introduced the bundling system for packets, which is a core component that allows packets to be processed together. We anticipate that modders may want to use this system, so we adapted it to accept custom payloads. You will find a `sendBundled(CustomPacketPayload... payloads)` method on the `ServerGamePacketListener`. {{< notice warning >}} -Packet bundling is only supported during the play phase of the network protocol. It can not be used during the configuration phase of the protocol. +Packet bundling is only supported during the play phase of the network protocol. It cannot be used during the configuration phase of the protocol. {{< /notice >}} ## Opening menus with custom data -In the past Forge supported opening UIs from the server side with additional data, via `NetworkHooks.openScreen(...)`. this system has been moved and is now part of the server `ServerPlayer` extension. You can call the method `openMenu` with the same parameters. +In the past, NeoForge supported opening UIs from the server side with additional data, via `NetworkHooks.openScreen(...)`. This system has been moved and is now part of the server `ServerPlayer` extension. You can call the method `openMenu` with the same parameters. ## Spawning entities with custom data -The previous networking implementation allowed for the spawning of custom entities via an overridden method on the `Entity` class: `getAddEntityPacket.` Modders that wanted to support custom additional data to be processed on the client side when the entity spawned, could override this method and return a packet from the method: `NetworkHooks.getEntitySpawningPacket(...)` +The previous networking implementation allowed spawning custom entities via an overridable method in the `Entity` class: `getAddEntityPacket.` Modders that wanted to support custom additional data to be processed on the client side when the entity spawned could override this method and return a packet from the method using `NetworkHooks.getEntitySpawningPacket(...)`. This system has now been refactored (as Mojang spawns and processes the entity packets with a bundle). The core of this new framework is the method `sendPairingData(ServerPlayer, Consumer)` on the `Entity` class. There are now two methods to configure this. ### Using a custom payload -By overriding the method and invoking the consumer with a custom payload, you are guaranteed that your payload will be processed immediately after the spawning packet. You are free to do whatever you want, however, we recommend you at least transfer the entity id, as vanilla does, to retrieve the entity instance when your packet arrives. +By overriding the method and invoking the consumer with a custom payload, you are guaranteeing that your payload will be processed immediately after the spawning packet. You are free to do whatever you want, however, we recommend you at least transfer the entity id, as vanilla does, to retrieve the entity instance when your packet arrives. ### Using the `IEntityWithComplexSpawn` interface -Implementing this interface on your entity forces you to implement two methods: `writeSpawnData` and `readSpawnData`. These methods, respectively, are invoked when an entity spawn bundle is generated and when the entity has been spawned. +Implementing this interface on your entity forces you to implement two methods: `writeSpawnData` and `readSpawnData`. These methods, are invoked when an entity spawn bundle is generated and when the entity has been spawned, respectively. ### Removal of custom entity creation code in `EntityType` -It is no longer possible to use the entity spawn packet code mentioned above to create a different entity class on the client side. This was due to the refactoring of the payload mechanics. And the reliance on the vanilla spawning bundle. +It is no longer possible to use the entity spawn packet code mentioned above to create a different entity class on the client side. This was due to the refactoring of the payload mechanics, and the reliance on the vanilla spawn bundle. -## Forge packet splitter -This PR reimplements the vanilla packet splitter forge, previously contained in Forge, and expands its usage to any packet (other than the packet sent when stuff is split). +## NeoForge packet splitter +The NeoForge packet splitter can now be used with any packet (other than the splitting packet itself). -Due to the new mechanics, a packet or payload is now roughly split into 8MB chunks, as per the vanilla protocol limitations. -## Mod-list transfer -Currently, the new protocol does not support sending the mod list across and only works on a channel and registry content basis. However, we do intend to work with the Fabric team on expanding the protocol in such a way that the server is made aware of what kind of mods the client has installed. +## Mod list transfer +Currently, the new protocol does not support sending the mod list across the network, and only works on a channel and registry content basis. However, we do intend to work with the Fabric team on expanding the protocol in such a way that the server is made aware of what kind of mods the client has installed. We deem this necessary to allow server owners to block mods that would allow cheating, for example, an XRay mod, etc. This will be added in another PR after further reviewing our stance and implementation possibilities.