Since Minecraft 1.19.4, the protocol supports bundling consecutive packets to ensure the client processes them in one tick. However, Packet Events are not called for the individual packets in such a bundle in the current dev build of ProtocolLib. For example, no packet events are currently sent for the ENTITY_METADATA packet when an entity is first spawned as the packet is bundled with the ENTITY_SPAWN packet. However, if the entity metadata is changed later on, the event will be called.
This PR proposes to fix this by unpacking the bundled packets and invoking the packet filtering for each packet.
I also want to briefly explain how the bundling works. A bundle starts with a PACKET_DELIMITER (0x00, net.minecraft.network.protocol.BundleDelimiterPacket) packet followed by all packets that should be bundled and finished with another PACKET_DELIMITER (0x00). Within the Netty pipeline, this sequence is transformed into one synthesized packet found in net.minecraft.network.protocol.game.ClientboundBundlePacket, which is essentially just a list of packets. At the stage at which ProtocolLib injects into the clientbound netty pipeline, this packet has not been unpacked yet. Thus, we need to handle the ClientboundBundlePacket, which unfortunately is not registered in ProtocolLib. The fact that two different classes map to the same packet currently requires a dirty remapping in the packet structure modifier.
* modified hashset collections for small performance gains
* reverted load factor modification since no noticeable performance gain was seen
---------
Co-authored-by: aseef <contact@aseef.dev>
* don't enforce async calls for thread-safe listeners (closes#1551)
* cleanups, remove structure compiling
* improve cloning a bit
* fix small issue in no-op structure modifier
* remove last usages of FieldUtils
* improve and fix equality check in container test
* Clear up some stuff, fix location of wire packet encoder
* Ensure that the player injection cache is always up-to-date
* Make uninjection from a channel more reliable
* Don't schedule an empty runnable if there is no need to do that
* Remove unnecessary throw declarations from some methods
* Adjust uninjection to remove the injector reference as well
* improve channel future injection in network manager
To note: this is yet another compatibility change for my Geyser work, but https://github.com/PaperMC/Paper/pull/5611 will also break without these changes as Unix domain sockets don't implement SocketChannel.
The temporary player method delegation directed the isOnline and getName methods to functions that require the channel to be an instance of SocketChannel, when this won't always be the case. To solve this, this PR redirects `getSocket().getRemoteSocketAddress()` to `injector.getAddress()` which returns the same value. To determine if the player is online, a new method is created in SocketInjector to determine if a connection is online (which also returns the same value as before this commit).
Fixes#1170.
The reasoning for this PR is largely outlined in the above issue. As the ChannelInboundHandlerAdapter has no private class, a race condition cannot occur and therefore marking the class as sharable should incur no cost.
- The gclib dependency in the EnchancerFactory has been removed. All classes that used the actual factory part of it have been updated to use bytebuddy instead. This class will have to be removed at some point, but at the moment it is still used for accessing its class loader.
- Renamed EnhancerFactory to ByteBuddyFactory. All ByteBuddy actions should go through this now. Every subclass created here implements the ByteBuddyGenerated interface. This makes it possible to recognize classes generated using ByteBuddy (by default, it doesn't leave such a trace).
- Removed the method DefaultInstances#forEnhancer(Enhancer). This method isn't used anywhere; the last trace of usage of the method I could find was in 2013 (in the NetworkServerInjector). External plugins (I couldn't find any that used it), they should really have their own implementation, given that they already require an instance of an Enchancer. As such, I feel it is safe to remove rather than update it.
Added an override to the encoder as such would process any non-wire packets as NMS packets. In the case of the use of different APIs, such as Artemis Packet API, such would cause a conflict and would spit out casting exceptions. It is quite easy to resolve by exclusively accepting Wire Packets and packets which are assignable to the packet class. This solves the issue and tada happy ending.
- Implemented a fix for the incompatibility with Java 15. This incompatibility was caused by the fact that the lambda generated in the NMS.NetworkManager is a hidden class in J15. Starting in Java 15, final fields in hidden classes can no longer be modified regardless of the 'accessible' flag. (see https://openjdk.java.net/jeps/371 "Using a hidden class", point 3). To circumvent this issue, this retrieves the data from the existing fields in the hidden class (a runnable or a callable) other than the packet. It then retrieves the constructor of the hidden class and instantiates it using the previously-retrieved data and the modified packet instance (this code is only used if the packet instance changed).
- Introduced a new ObjectReconstructor class that does all the fields/constructor discovering/accessing etc. The Runnable and Callable methods each get one instance of this class so that we can avoid having to get the fields/constructors and set them accessible every time we want to replace a packet.
Co-authored-by: Mark Vainomaa <mikroskeem@mikroskeem.eu>
Thanks to @KennyTV and @MedicOP for their help in tracking this bug down. Essentially the decode method we were using could be different depending on when the player logged in, which clashed with PL's static handling of it.
Fixes#724Fixes#791Fixes#803Fixes#811Fixes#813Fixes#819
...and probably some others...