SpigotMC / BungeeCord

BungeeCord, the 6th in a generation of server portal suites. Efficiently proxies and maintains connections and transport between multiple Minecraft servers.
https://www.spigotmc.org/go/bungeecord
Other
1.57k stars 1.1k forks source link

Dimension change screen doesn't show when switching from >=1.16 server to <1.16 server within the same dimension #2968

Open Fallen-Breath opened 4 years ago

Fallen-Breath commented 4 years ago

How to reproduce

Let's say there are 2 servers:

  1. serverA, Minecraft 1.16.3
  2. serverB, Minecraft 1.15.2

There is a player in serverA overworld, and he is switching to serverB (he is in the owerworld in serverB too). The player expects to see the dimension change screen for reloading the client thing when switching to serverB but he will not see that, which might cause some client desync things happen

You can reproduce this bug with any bungeecord that suports 1.16.x

For the way to switch between servers with different Minecraft version, you can use viaversion plugin for example to do so

Code analyzation

In net.md_5.bungee.ServerConnector#handle(net.md_5.bungee.protocol.packet.Login) method, when switching server with login.getDimension() instanceof Integer, there is an if judegement to decide if an extra Respawn packet should be sent to the client, to trick the client to display the dimension change screen when switching between the same dimension on two different servers

if ( login.getDimension() == user.getDimension() )
{
    user.unsafe().sendPacket( new Respawn( (Integer) login.getDimension() >= 0 ? -1 : 0, login.getWorldName(), login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(), false ) );
}

code permalink here

However, since the type of the dimension field are different between <1.16 and >=1.16 (int vs Tag or String), this if judgement will never become true in this situation, which causes this issue

Hacky workaround

A hacky workaround is removing this if ( login.getDimension() == user.getDimension() ) check and sending the Respawn packet anyway. And I think there won't be any issue except 1 more packet will be sent

if ( login.getDimension() == user.getDimension() || true )
{
    user.unsafe().sendPacket( new Respawn( (Integer) login.getDimension() >= 0 ? -1 : 0, login.getWorldName(), login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(), false ) );
}
Janmm14 commented 4 years ago

My guess is that you are using ViaVersion as a BungeeCord plugin, which is not supported by BungeeCord itself. Use it as Spigot plugin instead. That should fix this problem as bungee will only operate on 1.16-style data in that case.

Fallen-Breath commented 4 years ago

My guess is that you are using ViaVersion as a BungeeCord plugin, which is not supported by BungeeCord itself. Use it as Spigot plugin instead. That should fix this problem as bungee will only operate on 1.16-style data in that case.

the backend servers are vanilla servers so I can't do that

Janmm14 commented 4 years ago

In that case report the bug to ViaVersion.

Fallen-Breath commented 4 years ago

To make the client think the dimension has change in all cases, sending a Resapwn packet to another dimension before sending the target dimension Respawn packet can cover is a good choice I think. It's only a 1 line tweak to solve this problem in bungeecord and won't cause any issue. This edge-case bug fixing brings better compatibility with plugins and future possibile minecraft logic changes