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:
Ursprung
1616d097eb
Commit
48fafc73be
@ -43,6 +43,7 @@ dependencies {
|
||||
jar {
|
||||
manifest {
|
||||
attributes 'Main-Class': 'com.velocitypowered.proxy.Velocity'
|
||||
attributes 'Implementation-Version': project.version
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
147
src/main/java/com/velocitypowered/proxy/protocol/packets/BossBar.java
Normale Datei
147
src/main/java/com/velocitypowered/proxy/protocol/packets/BossBar.java
Normale Datei
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren