3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-12-24 23:30:26 +01:00

Correctly handle boss bars on server transfers

Dieser Commit ist enthalten in:
Andrew Steinborn 2018-07-30 01:03:42 -04:00
Ursprung 1616d097eb
Commit 48fafc73be
8 geänderte Dateien mit 203 neuen und 12 gelöschten Zeilen

Datei anzeigen

@ -43,6 +43,7 @@ dependencies {
jar {
manifest {
attributes 'Main-Class': 'com.velocitypowered.proxy.Velocity'
attributes 'Implementation-Version': project.version
}
}

Datei anzeigen

@ -2,11 +2,8 @@ package com.velocitypowered.proxy.connection.backend;
import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.packets.Disconnect;
import com.velocitypowered.proxy.protocol.packets.JoinGame;
import com.velocitypowered.proxy.protocol.packets.KeepAlive;
import com.velocitypowered.proxy.protocol.packets.*;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.packets.Respawn;
import io.netty.buffer.ByteBuf;
public class BackendPlaySessionHandler implements MinecraftSessionHandler {
@ -18,6 +15,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
@Override
public void handle(MinecraftPacket packet) {
ClientPlaySessionHandler playerHandler =
(ClientPlaySessionHandler) connection.getProxyPlayer().getConnection().getSessionHandler();
if (packet instanceof KeepAlive) {
// Forward onto the server
connection.getChannel().write(packet);
@ -25,15 +24,22 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
Disconnect original = (Disconnect) packet;
connection.getProxyPlayer().handleConnectionException(connection.getServerInfo(), original);
} else if (packet instanceof JoinGame) {
ClientPlaySessionHandler playerHandler =
(ClientPlaySessionHandler) connection.getProxyPlayer().getConnection().getSessionHandler();
playerHandler.handleBackendJoinGame((JoinGame) packet);
} else if (packet instanceof Respawn) {
// Record the dimension switch, and then forward the packet on.
ClientPlaySessionHandler playerHandler =
(ClientPlaySessionHandler) connection.getProxyPlayer().getConnection().getSessionHandler();
playerHandler.setCurrentDimension(((Respawn) packet).getDimension());
connection.getProxyPlayer().getConnection().write(packet);
} else if (packet instanceof BossBar) {
BossBar bossBar = (BossBar) packet;
switch (bossBar.getAction()) {
case 0: // add
playerHandler.getServerBossBars().add(bossBar.getUuid());
break;
case 1: // remove
playerHandler.getServerBossBars().remove(bossBar.getUuid());
break;
}
connection.getProxyPlayer().getConnection().write(packet);
} else {
// Just forward the packet on. We don't have anything to handle at this time.
connection.getProxyPlayer().getConnection().write(packet);

Datei anzeigen

@ -36,12 +36,13 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
if (packet instanceof ServerLoginSuccess) {
// The player has been logged on to the backend server.
connection.getChannel().setState(StateRegistry.PLAY);
if (connection.getProxyPlayer().getConnectedServer() == null) {
ServerConnection existingConnection = connection.getProxyPlayer().getConnectedServer();
if (existingConnection == null) {
// Strap on the play session handler
connection.getProxyPlayer().getConnection().setSessionHandler(new ClientPlaySessionHandler(connection.getProxyPlayer()));
} else {
// The previous server connection should become obsolete.
connection.getProxyPlayer().getConnectedServer().disconnect();
existingConnection.disconnect();
}
connection.getChannel().setSessionHandler(new BackendPlaySessionHandler(connection));
connection.getProxyPlayer().setConnectedServer(connection);

Datei anzeigen

@ -17,6 +17,8 @@ import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import io.netty.channel.*;
import io.netty.handler.timeout.ReadTimeoutHandler;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static com.velocitypowered.network.Connections.FRAME_DECODER;

Datei anzeigen

@ -15,6 +15,9 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@ -26,6 +29,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
private ScheduledFuture<?> pingTask;
private long lastPing = -1;
private boolean spawned = false;
private final List<UUID> serverBossBars = new ArrayList<>();
private int currentDimension;
public ClientPlaySessionHandler(ConnectedPlayer player) {
@ -105,7 +109,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
// nothing special to do here
spawned = true;
currentDimension = joinGame.getDimension();
player.getConnection().write(joinGame);
player.getConnection().delayedWrite(joinGame);
} else {
// In order to handle switching to another server we will need send three packets:
// - The join game packet from the backend server
@ -117,16 +121,32 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
int tempDim = joinGame.getDimension() == 0 ? -1 : 0;
player.getConnection().delayedWrite(new Respawn(tempDim, joinGame.getDifficulty(), joinGame.getGamemode(), joinGame.getLevelType()));
player.getConnection().delayedWrite(new Respawn(joinGame.getDimension(), joinGame.getDifficulty(), joinGame.getGamemode(), joinGame.getLevelType()));
player.getConnection().flush();
currentDimension = joinGame.getDimension();
}
// Resend client settings packet to remote server if we have it, this preserves client settings across
// transitions.
if (player.getClientSettings() != null) {
player.getConnectedServer().getChannel().write(player.getClientSettings());
}
// Remove old boss bars.
for (UUID serverBossBar : serverBossBars) {
BossBar deletePacket = new BossBar();
deletePacket.setUuid(serverBossBar);
deletePacket.setAction(1); // remove
player.getConnection().delayedWrite(deletePacket);
}
serverBossBars.clear();
player.getConnection().flush();
}
public void setCurrentDimension(int currentDimension) {
this.currentDimension = currentDimension;
}
public List<UUID> getServerBossBars() {
return serverBossBars;
}
}

Datei anzeigen

@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
public enum ProtocolUtils { ;
private static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB
@ -66,4 +67,15 @@ public enum ProtocolUtils { ;
writeVarInt(buf, array.length);
buf.writeBytes(array);
}
public static UUID readUuid(ByteBuf buf) {
long msb = buf.readLong();
long lsb = buf.readLong();
return new UUID(msb, lsb);
}
public static void writeUuid(ByteBuf buf, UUID uuid) {
buf.writeLong(uuid.getMostSignificantBits());
buf.writeLong(uuid.getLeastSignificantBits());
}
}

Datei anzeigen

@ -44,6 +44,8 @@ public enum StateRegistry {
map(0x05, MINECRAFT_1_12),
map(0x04, MINECRAFT_1_12_1));
CLIENTBOUND.register(BossBar.class, BossBar::new,
map(0x0C, MINECRAFT_1_11));
CLIENTBOUND.register(Chat.class, Chat::new,
map(0x0F, MINECRAFT_1_11));
CLIENTBOUND.register(Disconnect.class, Disconnect::new,

Datei anzeigen

@ -0,0 +1,147 @@
package com.velocitypowered.proxy.protocol.packets;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolConstants;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import io.netty.buffer.ByteBuf;
import java.util.UUID;
public class BossBar implements MinecraftPacket {
private UUID uuid;
private int action;
private String title;
private float health;
private int color;
private int divisions;
private short flags;
public UUID getUuid() {
return uuid;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
public int getAction() {
return action;
}
public void setAction(int action) {
this.action = action;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public float getHealth() {
return health;
}
public void setHealth(float health) {
this.health = health;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public int getDivisions() {
return divisions;
}
public void setDivisions(int divisions) {
this.divisions = divisions;
}
public short getFlags() {
return flags;
}
public void setFlags(short flags) {
this.flags = flags;
}
@Override
public String toString() {
return "BossBar{" +
"uuid=" + uuid +
", action=" + action +
", title='" + title + '\'' +
", health=" + health +
", color=" + color +
", divisions=" + divisions +
", flags=" + flags +
'}';
}
@Override
public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
this.uuid = ProtocolUtils.readUuid(buf);
this.action = ProtocolUtils.readVarInt(buf);
switch (action) {
case 0: // add
this.title = ProtocolUtils.readString(buf);
this.health = buf.readFloat();
this.color = ProtocolUtils.readVarInt(buf);
this.divisions = ProtocolUtils.readVarInt(buf);
this.flags = buf.readUnsignedByte();
break;
case 1: // remove
break;
case 2: // set health
this.health = buf.readFloat();
break;
case 3: // update title
this.title = ProtocolUtils.readString(buf);
break;
case 4: // update style
this.color = ProtocolUtils.readVarInt(buf);
this.divisions = ProtocolUtils.readVarInt(buf);
break;
case 5:
this.flags = buf.readUnsignedByte();
break;
}
}
@Override
public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
ProtocolUtils.writeUuid(buf, uuid);
ProtocolUtils.writeVarInt(buf, action);
switch (action) {
case 0: // add
ProtocolUtils.writeString(buf, title);
buf.writeFloat(health);
ProtocolUtils.writeVarInt(buf, color);
ProtocolUtils.writeVarInt(buf, divisions);
buf.writeByte(flags);
break;
case 1: // remove
break;
case 2: // set health
buf.writeFloat(health);
break;
case 3: // update title
ProtocolUtils.writeString(buf, title);
break;
case 4: // update style
ProtocolUtils.writeVarInt(buf, color);
ProtocolUtils.writeVarInt(buf, divisions);
break;
case 5:
buf.writeByte(flags);
break;
}
}
}