3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-11-17 05:20:14 +01:00

Very basic multi-server switching functionality

Dieser Commit ist enthalten in:
Andrew Steinborn 2018-07-26 17:18:59 -04:00
Ursprung 60ac285b17
Commit 6ae9798a1b
6 geänderte Dateien mit 247 neuen und 4 gelöschten Zeilen

Datei anzeigen

@ -33,11 +33,17 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
} }
if (packet instanceof ServerLoginSuccess) { if (packet instanceof ServerLoginSuccess) {
// the player has been logged on. // The player has been logged on to the backend server.
connection.getChannel().setState(StateRegistry.PLAY); connection.getChannel().setState(StateRegistry.PLAY);
connection.getProxyPlayer().setConnectedServer(connection); if (connection.getProxyPlayer().getConnectedServer() == null) {
connection.getProxyPlayer().getConnection().setSessionHandler(new com.velocitypowered.proxy.connection.client.PlaySessionHandler(connection.getProxyPlayer())); // Strap on the play session handler
connection.getProxyPlayer().getConnection().setSessionHandler(new com.velocitypowered.proxy.connection.client.PlaySessionHandler(connection.getProxyPlayer()));
} else {
// The previous server connection should become obsolete.
connection.getProxyPlayer().getConnectedServer().disconnect();
}
connection.getChannel().setSessionHandler(new PlaySessionHandler(connection)); connection.getChannel().setSessionHandler(new PlaySessionHandler(connection));
connection.getProxyPlayer().setConnectedServer(connection);
} }
} }

Datei anzeigen

@ -2,6 +2,7 @@ package com.velocitypowered.proxy.connection.backend;
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.Disconnect;
import com.velocitypowered.proxy.protocol.packets.JoinGame;
import com.velocitypowered.proxy.protocol.packets.Ping; import com.velocitypowered.proxy.protocol.packets.Ping;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
@ -31,6 +32,10 @@ public class PlaySessionHandler implements MinecraftSessionHandler {
.append(ComponentSerializers.JSON.deserialize(original.getReason())) .append(ComponentSerializers.JSON.deserialize(original.getReason()))
.build(); .build();
connection.getProxyPlayer().close(reason); connection.getProxyPlayer().close(reason);
} else if (packet instanceof JoinGame) {
com.velocitypowered.proxy.connection.client.PlaySessionHandler playerHandler =
(com.velocitypowered.proxy.connection.client.PlaySessionHandler) connection.getProxyPlayer().getConnection().getSessionHandler();
playerHandler.handleBackendJoinGame((JoinGame) 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);

Datei anzeigen

@ -1,11 +1,18 @@
package com.velocitypowered.proxy.connection.client; package com.velocitypowered.proxy.connection.client;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.backend.ServerConnection;
import com.velocitypowered.proxy.data.ServerInfo;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.packets.Chat;
import com.velocitypowered.proxy.protocol.packets.JoinGame;
import com.velocitypowered.proxy.protocol.packets.Ping; import com.velocitypowered.proxy.protocol.packets.Ping;
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;
import io.netty.channel.EventLoop; import io.netty.channel.EventLoop;
import java.net.InetSocketAddress;
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;
@ -14,6 +21,8 @@ public class PlaySessionHandler implements MinecraftSessionHandler {
private final ConnectedPlayer player; private final ConnectedPlayer player;
private ScheduledFuture<?> pingTask; private ScheduledFuture<?> pingTask;
private long lastPing = -1; private long lastPing = -1;
private boolean spawned = false;
private int currentDimension;
public PlaySessionHandler(ConnectedPlayer player) { public PlaySessionHandler(ConnectedPlayer player) {
this.player = player; this.player = player;
@ -38,12 +47,22 @@ public class PlaySessionHandler implements MinecraftSessionHandler {
if (packet instanceof Ping) { if (packet instanceof Ping) {
Ping ping = (Ping) packet; Ping ping = (Ping) packet;
if (ping.getRandomId() != lastPing) { if (ping.getRandomId() != lastPing) {
throw new IllegalStateException("Client sent invalid ping; expected " + lastPing + ", got " + ping.getRandomId()); // throw new IllegalStateException("Client sent invalid ping; expected " + lastPing + ", got " + ping.getRandomId());
} }
// Do not forward the packet to the player's server, because we handle pings for all servers already. // Do not forward the packet to the player's server, because we handle pings for all servers already.
return; return;
} }
if (packet instanceof Chat) {
Chat chat = (Chat) packet;
if (chat.getMessage().equals("/connect")) {
ServerInfo info = new ServerInfo("test", new InetSocketAddress("localhost", 25566));
ServerConnection connection = new ServerConnection(info, player, VelocityServer.getServer());
connection.connect();
}
}
// If we don't want to handle this packet, just forward it on. // If we don't want to handle this packet, just forward it on.
player.getConnectedServer().getChannel().write(packet); player.getConnectedServer().getChannel().write(packet);
} }
@ -62,4 +81,25 @@ public class PlaySessionHandler implements MinecraftSessionHandler {
pingTask = null; pingTask = null;
} }
} }
public void handleBackendJoinGame(JoinGame joinGame) {
if (!spawned) {
// nothing special to do here
spawned = true;
currentDimension = joinGame.getDimension();
player.getConnection().write(joinGame);
} else {
// In order to handle switching to another server we will need send three packets:
// - The join game packet
// - A respawn packet, with a different dimension, if it differs
// - Another respawn with the correct dimension
player.getConnection().write(joinGame);
if (joinGame.getDimension() == currentDimension) {
int tempDim = joinGame.getDimension() == 0 ? -1 : 0;
player.getConnection().write(new Respawn(tempDim, joinGame.getDifficulty(), joinGame.getGamemode(), joinGame.getLevelType()));
}
player.getConnection().write(new Respawn(joinGame.getDimension(), joinGame.getDifficulty(), joinGame.getGamemode(), joinGame.getLevelType()));
currentDimension = joinGame.getDimension();
}
}
} }

Datei anzeigen

@ -47,6 +47,10 @@ public enum StateRegistry {
map(0x1A, MINECRAFT_1_12)); map(0x1A, MINECRAFT_1_12));
TO_CLIENT.register(Ping.class, Ping::new, TO_CLIENT.register(Ping.class, Ping::new,
map(0x1F, MINECRAFT_1_12)); map(0x1F, MINECRAFT_1_12));
TO_CLIENT.register(JoinGame.class, JoinGame::new,
map(0x23, MINECRAFT_1_12));
TO_CLIENT.register(Respawn.class, Respawn::new,
map(0x35, MINECRAFT_1_12));
} }
}, },
LOGIN { LOGIN {

Datei anzeigen

@ -0,0 +1,107 @@
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;
public class JoinGame implements MinecraftPacket {
private int entityId;
private short gamemode;
private int dimension;
private short difficulty;
private short maxPlayers;
private String levelType;
private boolean reducedDebugInfo;
public int getEntityId() {
return entityId;
}
public void setEntityId(int entityId) {
this.entityId = entityId;
}
public short getGamemode() {
return gamemode;
}
public void setGamemode(short gamemode) {
this.gamemode = gamemode;
}
public int getDimension() {
return dimension;
}
public void setDimension(int dimension) {
this.dimension = dimension;
}
public short getDifficulty() {
return difficulty;
}
public void setDifficulty(short difficulty) {
this.difficulty = difficulty;
}
public short getMaxPlayers() {
return maxPlayers;
}
public void setMaxPlayers(short maxPlayers) {
this.maxPlayers = maxPlayers;
}
public String getLevelType() {
return levelType;
}
public void setLevelType(String levelType) {
this.levelType = levelType;
}
public boolean isReducedDebugInfo() {
return reducedDebugInfo;
}
public void setReducedDebugInfo(boolean reducedDebugInfo) {
this.reducedDebugInfo = reducedDebugInfo;
}
@Override
public String toString() {
return "JoinGame{" +
"entityId=" + entityId +
", gamemode=" + gamemode +
", dimension=" + dimension +
", difficulty=" + difficulty +
", maxPlayers=" + maxPlayers +
", levelType='" + levelType + '\'' +
", reducedDebugInfo=" + reducedDebugInfo +
'}';
}
@Override
public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
this.entityId = buf.readInt();
this.gamemode = buf.readUnsignedByte();
this.dimension = buf.readInt();
this.difficulty = buf.readUnsignedByte();
this.maxPlayers = buf.readUnsignedByte();
this.levelType = ProtocolUtils.readString(buf, 16);
this.reducedDebugInfo = buf.readBoolean();
}
@Override
public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
buf.writeInt(entityId);
buf.writeByte(gamemode);
buf.writeInt(dimension);
buf.writeByte(difficulty);
buf.writeByte(maxPlayers);
ProtocolUtils.writeString(buf, levelType);
buf.writeBoolean(reducedDebugInfo);
}
}

Datei anzeigen

@ -0,0 +1,81 @@
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;
public class Respawn implements MinecraftPacket {
private int dimension;
private short difficulty;
private short gamemode;
private String levelType;
public Respawn() {
}
public Respawn(int dimension, short difficulty, short gamemode, String levelType) {
this.dimension = dimension;
this.difficulty = difficulty;
this.gamemode = gamemode;
this.levelType = levelType;
}
public int getDimension() {
return dimension;
}
public void setDimension(int dimension) {
this.dimension = dimension;
}
public short getDifficulty() {
return difficulty;
}
public void setDifficulty(short difficulty) {
this.difficulty = difficulty;
}
public short getGamemode() {
return gamemode;
}
public void setGamemode(short gamemode) {
this.gamemode = gamemode;
}
public String getLevelType() {
return levelType;
}
public void setLevelType(String levelType) {
this.levelType = levelType;
}
@Override
public String toString() {
return "Respawn{" +
"dimension=" + dimension +
", difficulty=" + difficulty +
", gamemode=" + gamemode +
", levelType='" + levelType + '\'' +
'}';
}
@Override
public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
this.dimension = buf.readInt();
this.difficulty = buf.readUnsignedByte();
this.gamemode = buf.readUnsignedByte();
this.levelType = ProtocolUtils.readString(buf, 16);
}
@Override
public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
buf.writeInt(dimension);
buf.writeByte(difficulty);
buf.writeByte(gamemode);
ProtocolUtils.writeString(buf, levelType);
}
}