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:
Ursprung
60ac285b17
Commit
6ae9798a1b
@ -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) {
|
||||||
|
// Strap on the play session handler
|
||||||
connection.getProxyPlayer().getConnection().setSessionHandler(new com.velocitypowered.proxy.connection.client.PlaySessionHandler(connection.getProxyPlayer()));
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
107
src/main/java/com/velocitypowered/proxy/protocol/packets/JoinGame.java
Normale Datei
107
src/main/java/com/velocitypowered/proxy/protocol/packets/JoinGame.java
Normale Datei
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren