ProtocolLib

3M Downloads

TinyProtocol: If player joins directly at server start, NPE on PlayerLoginEvent is thrown and no packets are received

Olexorus opened this issue ยท 1 comments

commented

I'm using TinyProtocol to listen to KeepAlive packets to calculate the player ping accurately (because the NMS ping seems a bit random, or at least unaccurate, not sure why).

Generally this works really well, however when a player joins while the server is still loading (happens all the time if there are short restarts since people will try to get back on as soon as possible), a NPE is thrown. On top of that, intercepting packets doesn't work for those players afterwards.

Error message:

[12:22:11 INFO]: UUID of player Olexorus is 9c18e988-1a7d-4a79-b0bd-fd731e6fe655
[12:22:11 ERROR]: Could not pass event PlayerLoginEvent to WitherAC v0.10.1
java.lang.NullPointerException: null
	at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(Unknown Source) ~[?:1.8.0_211]
	at sun.reflect.UnsafeQualifiedObjectFieldAccessorImpl.get(Unknown Source) ~[?:1.8.0_211]
	at java.lang.reflect.Field.get(Unknown Source) ~[?:1.8.0_211]
	at com.comphenix.tinyprotocol.Reflection$1.get(Reflection.java:149) ~[?:?]
	at com.comphenix.tinyprotocol.TinyProtocol.getChannel(TinyProtocol.java:397) ~[?:?]
	at com.comphenix.tinyprotocol.TinyProtocol$5.onPlayerLogin(TinyProtocol.java:176) ~[?:?]
	at com.destroystokyo.paper.event.executor.MethodHandleEventExecutor.execute(MethodHandleEventExecutor.java:37) ~[patched_1.14.3.jar:git-Paper-115]
	at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:80) ~[patched_1.14.3.jar:git-Paper-115]
	at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[patched_1.14.3.jar:git-Paper-115]
	at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:536) ~[patched_1.14.3.jar:git-Paper-115]
	at net.minecraft.server.v1_14_R1.PlayerList.attemptLogin(PlayerList.java:545) ~[patched_1.14.3.jar:git-Paper-115]
	at net.minecraft.server.v1_14_R1.LoginListener.c(LoginListener.java:149) ~[patched_1.14.3.jar:git-Paper-115]
	at net.minecraft.server.v1_14_R1.LoginListener.tick(LoginListener.java:65) ~[patched_1.14.3.jar:git-Paper-115]
	at net.minecraft.server.v1_14_R1.NetworkManager.a(NetworkManager.java:255) ~[patched_1.14.3.jar:git-Paper-115]
	at net.minecraft.server.v1_14_R1.ServerConnection.c(ServerConnection.java:129) ~[patched_1.14.3.jar:git-Paper-115]
	at net.minecraft.server.v1_14_R1.MinecraftServer.b(MinecraftServer.java:1216) ~[patched_1.14.3.jar:git-Paper-115]
	at net.minecraft.server.v1_14_R1.DedicatedServer.b(DedicatedServer.java:420) ~[patched_1.14.3.jar:git-Paper-115]
	at net.minecraft.server.v1_14_R1.MinecraftServer.a(MinecraftServer.java:1064) ~[patched_1.14.3.jar:git-Paper-115]
	at net.minecraft.server.v1_14_R1.MinecraftServer.run(MinecraftServer.java:908) ~[patched_1.14.3.jar:git-Paper-115]
	at java.lang.Thread.run(Unknown Source) [?:1.8.0_211]
[12:22:11 INFO]: Olexorus[/127.0.0.1:52494] logged in with entity id 87 at ([world]119.1430354820524, 73.0, -178.06247045625403)

Relevant plugin code:

object : TinyProtocol(WitherAC.INSTANCE) {

            private val KEEP_ALIVE_IN_CLASS = Reflection.getClass("{nms}.PacketPlayInKeepAlive")
            private val KEEP_ALIVE_OUT_CLASS = Reflection.getClass("{nms}.PacketPlayOutKeepAlive")

            override fun onPacketInAsync(player: Player?, channel: Channel?, packet: Any?): Any {
                if (KEEP_ALIVE_IN_CLASS.isInstance(packet)) {
                    val data = DataManager.getGeneralData(player!!)
                    data.ping = timeSince(data.lastKeepAlive).toInt()
                }
                return super.onPacketInAsync(player, channel, packet)
            }

            override fun onPacketOutAsync(player: Player?, channel: Channel?, packet: Any?): Any {
                if (KEEP_ALIVE_OUT_CLASS.isInstance(packet)) {
                    val data = DataManager.getGeneralData(player!!)
                    data.lastKeepAlive = System.currentTimeMillis()
                }
                return super.onPacketOutAsync(player, channel, packet)
            }
        }

This code is called in the constructor of a class which is created in the onEnable() method of my plugin. If it's a problem that this is Kotlin code, I can translate it into Java.

Server version: The error log is from Paper 1.14.3 build 115, but I also tested it on the latest Paper build (127) and on Spigot 1.13.2.

I am using the latest TinyProtocol and Reflection sources files, directly from this repository.

If my plugin is needed for testing it can be downloaded from Spigot, I can also provide the obfuscation mappings if necessary (even though I doubt it's related to my plugin since the stacktrace points to TinyProtocol's code).

commented

I believe I was able to fix it by changing the argument of void onPlayerLogin(PlayerLoginEvent) to PlayerJoinEvent, probably because that event is fired later.

I have no idea if this creates any new problems, but for me it seems to work.