Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-17 05:20:14 +01:00
Correctly handle boss bars on server transfers
Dieser Commit ist enthalten in:
Ursprung
1616d097eb
Commit
48fafc73be
@ -43,6 +43,7 @@ dependencies {
|
|||||||
jar {
|
jar {
|
||||||
manifest {
|
manifest {
|
||||||
attributes 'Main-Class': 'com.velocitypowered.proxy.Velocity'
|
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.connection.client.ClientPlaySessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packets.Disconnect;
|
import com.velocitypowered.proxy.protocol.packets.*;
|
||||||
import com.velocitypowered.proxy.protocol.packets.JoinGame;
|
|
||||||
import com.velocitypowered.proxy.protocol.packets.KeepAlive;
|
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.packets.Respawn;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||||
@ -18,6 +15,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(MinecraftPacket packet) {
|
public void handle(MinecraftPacket packet) {
|
||||||
|
ClientPlaySessionHandler playerHandler =
|
||||||
|
(ClientPlaySessionHandler) connection.getProxyPlayer().getConnection().getSessionHandler();
|
||||||
if (packet instanceof KeepAlive) {
|
if (packet instanceof KeepAlive) {
|
||||||
// Forward onto the server
|
// Forward onto the server
|
||||||
connection.getChannel().write(packet);
|
connection.getChannel().write(packet);
|
||||||
@ -25,15 +24,22 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
Disconnect original = (Disconnect) packet;
|
Disconnect original = (Disconnect) packet;
|
||||||
connection.getProxyPlayer().handleConnectionException(connection.getServerInfo(), original);
|
connection.getProxyPlayer().handleConnectionException(connection.getServerInfo(), original);
|
||||||
} else if (packet instanceof JoinGame) {
|
} else if (packet instanceof JoinGame) {
|
||||||
ClientPlaySessionHandler playerHandler =
|
|
||||||
(ClientPlaySessionHandler) connection.getProxyPlayer().getConnection().getSessionHandler();
|
|
||||||
playerHandler.handleBackendJoinGame((JoinGame) packet);
|
playerHandler.handleBackendJoinGame((JoinGame) packet);
|
||||||
} else if (packet instanceof Respawn) {
|
} else if (packet instanceof Respawn) {
|
||||||
// Record the dimension switch, and then forward the packet on.
|
// Record the dimension switch, and then forward the packet on.
|
||||||
ClientPlaySessionHandler playerHandler =
|
|
||||||
(ClientPlaySessionHandler) connection.getProxyPlayer().getConnection().getSessionHandler();
|
|
||||||
playerHandler.setCurrentDimension(((Respawn) packet).getDimension());
|
playerHandler.setCurrentDimension(((Respawn) packet).getDimension());
|
||||||
connection.getProxyPlayer().getConnection().write(packet);
|
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 {
|
} else {
|
||||||
// Just forward the packet on. We don't have anything to handle at this time.
|
// Just forward the packet on. We don't have anything to handle at this time.
|
||||||
connection.getProxyPlayer().getConnection().write(packet);
|
connection.getProxyPlayer().getConnection().write(packet);
|
||||||
|
@ -36,12 +36,13 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
if (packet instanceof ServerLoginSuccess) {
|
if (packet instanceof ServerLoginSuccess) {
|
||||||
// The player has been logged on to the backend server.
|
// The player has been logged on to the backend server.
|
||||||
connection.getChannel().setState(StateRegistry.PLAY);
|
connection.getChannel().setState(StateRegistry.PLAY);
|
||||||
if (connection.getProxyPlayer().getConnectedServer() == null) {
|
ServerConnection existingConnection = connection.getProxyPlayer().getConnectedServer();
|
||||||
|
if (existingConnection == null) {
|
||||||
// Strap on the play session handler
|
// Strap on the play session handler
|
||||||
connection.getProxyPlayer().getConnection().setSessionHandler(new ClientPlaySessionHandler(connection.getProxyPlayer()));
|
connection.getProxyPlayer().getConnection().setSessionHandler(new ClientPlaySessionHandler(connection.getProxyPlayer()));
|
||||||
} else {
|
} else {
|
||||||
// The previous server connection should become obsolete.
|
// The previous server connection should become obsolete.
|
||||||
connection.getProxyPlayer().getConnectedServer().disconnect();
|
existingConnection.disconnect();
|
||||||
}
|
}
|
||||||
connection.getChannel().setSessionHandler(new BackendPlaySessionHandler(connection));
|
connection.getChannel().setSessionHandler(new BackendPlaySessionHandler(connection));
|
||||||
connection.getProxyPlayer().setConnectedServer(connection);
|
connection.getProxyPlayer().setConnectedServer(connection);
|
||||||
|
@ -17,6 +17,8 @@ import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
|||||||
import io.netty.channel.*;
|
import io.netty.channel.*;
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static com.velocitypowered.network.Connections.FRAME_DECODER;
|
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 org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
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.ScheduledFuture;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -26,6 +29,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
private ScheduledFuture<?> pingTask;
|
private ScheduledFuture<?> pingTask;
|
||||||
private long lastPing = -1;
|
private long lastPing = -1;
|
||||||
private boolean spawned = false;
|
private boolean spawned = false;
|
||||||
|
private final List<UUID> serverBossBars = new ArrayList<>();
|
||||||
private int currentDimension;
|
private int currentDimension;
|
||||||
|
|
||||||
public ClientPlaySessionHandler(ConnectedPlayer player) {
|
public ClientPlaySessionHandler(ConnectedPlayer player) {
|
||||||
@ -105,7 +109,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
// nothing special to do here
|
// nothing special to do here
|
||||||
spawned = true;
|
spawned = true;
|
||||||
currentDimension = joinGame.getDimension();
|
currentDimension = joinGame.getDimension();
|
||||||
player.getConnection().write(joinGame);
|
player.getConnection().delayedWrite(joinGame);
|
||||||
} else {
|
} else {
|
||||||
// In order to handle switching to another server we will need send three packets:
|
// In order to handle switching to another server we will need send three packets:
|
||||||
// - The join game packet from the backend server
|
// - The join game packet from the backend server
|
||||||
@ -117,16 +121,32 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
int tempDim = joinGame.getDimension() == 0 ? -1 : 0;
|
int tempDim = joinGame.getDimension() == 0 ? -1 : 0;
|
||||||
player.getConnection().delayedWrite(new Respawn(tempDim, joinGame.getDifficulty(), joinGame.getGamemode(), joinGame.getLevelType()));
|
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().delayedWrite(new Respawn(joinGame.getDimension(), joinGame.getDifficulty(), joinGame.getGamemode(), joinGame.getLevelType()));
|
||||||
player.getConnection().flush();
|
|
||||||
currentDimension = joinGame.getDimension();
|
currentDimension = joinGame.getDimension();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resend client settings packet to remote server if we have it, this preserves client settings across
|
||||||
|
// transitions.
|
||||||
if (player.getClientSettings() != null) {
|
if (player.getClientSettings() != null) {
|
||||||
player.getConnectedServer().getChannel().write(player.getClientSettings());
|
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) {
|
public void setCurrentDimension(int currentDimension) {
|
||||||
this.currentDimension = 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 io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public enum ProtocolUtils { ;
|
public enum ProtocolUtils { ;
|
||||||
private static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB
|
private static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB
|
||||||
@ -66,4 +67,15 @@ public enum ProtocolUtils { ;
|
|||||||
writeVarInt(buf, array.length);
|
writeVarInt(buf, array.length);
|
||||||
buf.writeBytes(array);
|
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(0x05, MINECRAFT_1_12),
|
||||||
map(0x04, MINECRAFT_1_12_1));
|
map(0x04, MINECRAFT_1_12_1));
|
||||||
|
|
||||||
|
CLIENTBOUND.register(BossBar.class, BossBar::new,
|
||||||
|
map(0x0C, MINECRAFT_1_11));
|
||||||
CLIENTBOUND.register(Chat.class, Chat::new,
|
CLIENTBOUND.register(Chat.class, Chat::new,
|
||||||
map(0x0F, MINECRAFT_1_11));
|
map(0x0F, MINECRAFT_1_11));
|
||||||
CLIENTBOUND.register(Disconnect.class, Disconnect::new,
|
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