ProtocolLib

3M Downloads

[1.20.2] RESPAWN packet error

ThomasMo54 opened this issue ยท 4 comments

commented
  • This issue is not solved in a development build

Describe the bug
Back in 1.19.4 I was using this piece of code to send a respawn packet to a player and it worked fine:

val respawnPacket = protocolManager.createPacket(PacketType.Play.Server.RESPAWN)
val dimensionType = respawnPacket.structures.read(0)
dimensionType.minecraftKeys.write(0, MinecraftKey("minecraft", "dimension_type"))
dimensionType.minecraftKeys.write(1, MinecraftKey("minecraft", "overworld"))
respawnPacket.structures.write(0, dimensionType)
respawnPacket.longs.write(0, 0L)
respawnPacket.worldKeys.write(0, player.world)
respawnPacket.gameModes.write(0, EnumWrappers.NativeGameMode.fromBukkit(player.gameMode))
respawnPacket.gameModes.write(1, EnumWrappers.NativeGameMode.fromBukkit(player.gameMode))
respawnPacket.booleans.write(0, false)
respawnPacket.booleans.write(1, false)
respawnPacket.booleans.writeSafely(2, false)
respawnPacket.getOptionals(Converters.passthrough(Object::class.java)).write(0, Optional.empty())

However since I updated my server to 1.20.2 this code does not work anymore, here's the thrown exception:

com.comphenix.protocol.reflect.FieldAccessException: Field index 0 is out of bounds for length 0
        at com.comphenix.protocol.reflect.FieldAccessException.fromFormat(FieldAccessException.java:49) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.reflect.StructureModifier.write(StructureModifier.java:316) ~[ProtocolLib.jar:?]
        at com.mineofwar.minecraft.common.paper.core.player.InternalPlayer.updateSkin(InternalPlayer.kt:278) ~[lobby-local.jar:?]
        at com.mineofwar.minecraft.common.paper.core.player.InternalPlayer.nick$lambda$19(InternalPlayer.kt:332) ~[lobby-local.jar:?]
        at org.bukkit.craftbukkit.v1_20_R2.scheduler.CraftTask.run(CraftTask.java:101) ~[paper-1.20.2.jar:git-Paper-246]
        at org.bukkit.craftbukkit.v1_20_R2.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:480) ~[paper-1.20.2.jar:git-Paper-246]
        at net.minecraft.server.MinecraftServer.tickChildren(MinecraftServer.java:1470) ~[paper-1.20.2.jar:git-Paper-246]
        at net.minecraft.server.dedicated.DedicatedServer.tickChildren(DedicatedServer.java:446) ~[paper-1.20.2.jar:git-Paper-246]
        at net.minecraft.server.MinecraftServer.tickServer(MinecraftServer.java:1379) ~[paper-1.20.2.jar:git-Paper-246]
        at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1156) ~[paper-1.20.2.jar:git-Paper-246]
        at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:315) ~[paper-1.20.2.jar:git-Paper-246]
        at java.lang.Thread.run(Thread.java:833) ~[?:?]

Note that InternalPlayer.kt:278 refers to the dimensionType.minecraftKeys.write(0, MinecraftKey("minecraft", "dimension_type")) line.
I suppose that the packet structure changed in 1.20.x but i can't find the updated one.

Version Info
Version info.

commented

After some investigations it seems like the packet structure has indeed changed. It now only contains a CommonPlayerSpawnInfo object that contains all the previous packet data.

Can we expect that a support for this object will be added in the future? If not I would be glad to know how to make things work without it.

Here's what the packet structure looks like when I print it in the console :

net.minecraft.network.protocol.game.PacketPlayOutRespawn@4038b7b7[
    d=CommonPlayerSpawnInfo[dimensionType=ResourceKey[minecraft:dimension_type / minecraft:overworld], dimension=ResourceKey[minecraft:dimension / minecraft:overworld], seed=6667425060927977019, gameType=SURVIVAL, previousGameType=CREATIVE, isDebug=false, isFlat=false, lastDeathLocation=Optional[ResourceKey[minecraft:dimension / minecraft:overworld] BlockPosition{x=2, y=66, z=6}], portalCooldown=0]
    e=0
  ]
commented

After some investigations it seems like the packet structure has indeed changed. It now only contains a CommonPlayerSpawnInfo object that contains all the previous packet data.

Can we expect that a support for this object will be added in the future? If not I would be glad to know how to make things work without it.

Here's what the packet structure looks like when I print it in the console :

net.minecraft.network.protocol.game.PacketPlayOutRespawn@4038b7b7[
    d=CommonPlayerSpawnInfo[dimensionType=ResourceKey[minecraft:dimension_type / minecraft:overworld], dimension=ResourceKey[minecraft:dimension / minecraft:overworld], seed=6667425060927977019, gameType=SURVIVAL, previousGameType=CREATIVE, isDebug=false, isFlat=false, lastDeathLocation=Optional[ResourceKey[minecraft:dimension / minecraft:overworld] BlockPosition{x=2, y=66, z=6}], portalCooldown=0]
    e=0
  ]

Were you able to figure out a way to work around it?

commented

After some investigations it seems like the packet structure has indeed changed. It now only contains a CommonPlayerSpawnInfo object that contains all the previous packet data.
Can we expect that a support for this object will be added in the future? If not I would be glad to know how to make things work without it.
Here's what the packet structure looks like when I print it in the console :

net.minecraft.network.protocol.game.PacketPlayOutRespawn@4038b7b7[
    d=CommonPlayerSpawnInfo[dimensionType=ResourceKey[minecraft:dimension_type / minecraft:overworld], dimension=ResourceKey[minecraft:dimension / minecraft:overworld], seed=6667425060927977019, gameType=SURVIVAL, previousGameType=CREATIVE, isDebug=false, isFlat=false, lastDeathLocation=Optional[ResourceKey[minecraft:dimension / minecraft:overworld] BlockPosition{x=2, y=66, z=6}], portalCooldown=0]
    e=0
  ]

Were you able to figure out a way to work around it?

Yes! You just need to set all the fields inside a structure instead of the packet directly. Here's what I have :

val respawnPacket = protocolManager.createPacket(PacketType.Play.Server.RESPAWN)
val playerSpawnInfo = respawnPacket.structures.read(0)
playerSpawnInfo.dimensionTypes.writeSafely(0, player.world)
getDimensionType(player.world)?.let { playerSpawnInfo.modifier.write(0, it) }
playerSpawnInfo.longs.write(0, Hashing.sha256().hashLong(player.world.seed).asLong())
playerSpawnInfo.worldKeys.write(0, player.world)
playerSpawnInfo.gameModes.write(0, EnumWrappers.NativeGameMode.fromBukkit(player.gameMode))
playerSpawnInfo.gameModes.write(1, EnumWrappers.NativeGameMode.fromBukkit(player.gameMode))
playerSpawnInfo.booleans.write(0, false)
playerSpawnInfo.booleans.write(1, false)
playerSpawnInfo.booleans.writeSafely(2, false)
respawnPacket.structures.write(0, playerSpawnInfo)

Working perfectly.

commented

After some investigations it seems like the packet structure has indeed changed. It now only contains a CommonPlayerSpawnInfo object that contains all the previous packet data.
Can we expect that a support for this object will be added in the future? If not I would be glad to know how to make things work without it.
Here's what the packet structure looks like when I print it in the console :

net.minecraft.network.protocol.game.PacketPlayOutRespawn@4038b7b7[
    d=CommonPlayerSpawnInfo[dimensionType=ResourceKey[minecraft:dimension_type / minecraft:overworld], dimension=ResourceKey[minecraft:dimension / minecraft:overworld], seed=6667425060927977019, gameType=SURVIVAL, previousGameType=CREATIVE, isDebug=false, isFlat=false, lastDeathLocation=Optional[ResourceKey[minecraft:dimension / minecraft:overworld] BlockPosition{x=2, y=66, z=6}], portalCooldown=0]
    e=0
  ]

Were you able to figure out a way to work around it?

Yes! You just need to set all the fields inside a structure instead of the packet directly. Here's what I have :

val respawnPacket = protocolManager.createPacket(PacketType.Play.Server.RESPAWN)
val playerSpawnInfo = respawnPacket.structures.read(0)
playerSpawnInfo.dimensionTypes.writeSafely(0, player.world)
getDimensionType(player.world)?.let { playerSpawnInfo.modifier.write(0, it) }
playerSpawnInfo.longs.write(0, Hashing.sha256().hashLong(player.world.seed).asLong())
playerSpawnInfo.worldKeys.write(0, player.world)
playerSpawnInfo.gameModes.write(0, EnumWrappers.NativeGameMode.fromBukkit(player.gameMode))
playerSpawnInfo.gameModes.write(1, EnumWrappers.NativeGameMode.fromBukkit(player.gameMode))
playerSpawnInfo.booleans.write(0, false)
playerSpawnInfo.booleans.write(1, false)
playerSpawnInfo.booleans.writeSafely(2, false)
respawnPacket.structures.write(0, playerSpawnInfo)

Working perfectly.

Sorry for reopening this thread, but how did you get the Dimension type? I cant find any resources online explaining this.