Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-17 05:20:14 +01:00
Finished the port to new session handler stuff
Dieser Commit ist enthalten in:
Ursprung
c7bd0d100e
Commit
79d566bcee
@ -6,7 +6,6 @@ import com.velocitypowered.api.command.CommandManager;
|
|||||||
import com.velocitypowered.api.command.CommandSource;
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class VelocityCommandManager implements CommandManager {
|
public class VelocityCommandManager implements CommandManager {
|
||||||
private final Map<String, Command> commands = new HashMap<>();
|
private final Map<String, Command> commands = new HashMap<>();
|
||||||
@ -57,6 +56,10 @@ public class VelocityCommandManager implements CommandManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasCommand(String command) {
|
||||||
|
return commands.containsKey(command);
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<List<String>> offerSuggestions(CommandSource source, String cmdLine) {
|
public Optional<List<String>> offerSuggestions(CommandSource source, String cmdLine) {
|
||||||
Preconditions.checkNotNull(source, "source");
|
Preconditions.checkNotNull(source, "source");
|
||||||
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
||||||
|
@ -69,12 +69,19 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
|
|||||||
@Override
|
@Override
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
if (msg instanceof MinecraftPacket) {
|
if (msg instanceof MinecraftPacket) {
|
||||||
|
if (sessionHandler.beforeHandle()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MinecraftPacket pkt = (MinecraftPacket) msg;
|
MinecraftPacket pkt = (MinecraftPacket) msg;
|
||||||
if (!pkt.handle(sessionHandler)) {
|
if (!pkt.handle(sessionHandler)) {
|
||||||
sessionHandler.handleGeneric((MinecraftPacket) msg);
|
sessionHandler.handleGeneric((MinecraftPacket) msg);
|
||||||
}
|
}
|
||||||
} else if (msg instanceof ByteBuf) {
|
} else if (msg instanceof ByteBuf) {
|
||||||
try {
|
try {
|
||||||
|
if (sessionHandler.beforeHandle()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
sessionHandler.handleUnknown((ByteBuf) msg);
|
sessionHandler.handleUnknown((ByteBuf) msg);
|
||||||
} finally {
|
} finally {
|
||||||
ReferenceCountUtil.release(msg);
|
ReferenceCountUtil.release(msg);
|
||||||
|
@ -5,10 +5,16 @@ import com.velocitypowered.proxy.protocol.packet.*;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public interface MinecraftSessionHandler {
|
public interface MinecraftSessionHandler {
|
||||||
void handleGeneric(MinecraftPacket packet);
|
default boolean beforeHandle() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
default void handleGeneric(MinecraftPacket packet) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
default void handleUnknown(ByteBuf buf) {
|
default void handleUnknown(ByteBuf buf) {
|
||||||
// No-op: we'll release the buffer later.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default void connected() {
|
default void connected() {
|
||||||
|
@ -17,10 +17,12 @@ import io.netty.buffer.ByteBuf;
|
|||||||
public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||||
private final VelocityServer server;
|
private final VelocityServer server;
|
||||||
private final VelocityServerConnection serverConn;
|
private final VelocityServerConnection serverConn;
|
||||||
|
private final ClientPlaySessionHandler playerSessionHandler;
|
||||||
|
|
||||||
public BackendPlaySessionHandler(VelocityServer server, VelocityServerConnection serverConn) {
|
public BackendPlaySessionHandler(VelocityServer server, VelocityServerConnection serverConn) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.serverConn = serverConn;
|
this.serverConn = serverConn;
|
||||||
|
this.playerSessionHandler = (ClientPlaySessionHandler) serverConn.getPlayer().getConnection().getSessionHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -29,6 +31,93 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
serverConn.getServer().addPlayer(serverConn.getPlayer());
|
serverConn.getServer().addPlayer(serverConn.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean beforeHandle() {
|
||||||
|
if (!serverConn.getPlayer().isActive()) {
|
||||||
|
// Obsolete connection
|
||||||
|
serverConn.disconnect();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(KeepAlive packet) {
|
||||||
|
serverConn.setLastPingId(packet.getRandomId());
|
||||||
|
return false; // forwards on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(Disconnect packet) {
|
||||||
|
serverConn.disconnect();
|
||||||
|
serverConn.getPlayer().handleConnectionException(serverConn.getServer(), packet);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(JoinGame packet) {
|
||||||
|
playerSessionHandler.handleBackendJoinGame(packet);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(BossBar packet) {
|
||||||
|
switch (packet.getAction()) {
|
||||||
|
case 0: // add
|
||||||
|
playerSessionHandler.getServerBossBars().add(packet.getUuid());
|
||||||
|
break;
|
||||||
|
case 1: // remove
|
||||||
|
playerSessionHandler.getServerBossBars().remove(packet.getUuid());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false; // forward
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(PluginMessage packet) {
|
||||||
|
if (!canForwardPluginMessage(packet)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PluginMessageUtil.isMCBrand(packet)) {
|
||||||
|
serverConn.getPlayer().getConnection().write(PluginMessageUtil.rewriteMCBrand(packet));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverConn.hasCompletedJoin() && packet.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) {
|
||||||
|
if (!serverConn.isLegacyForge()) {
|
||||||
|
serverConn.setLegacyForge(true);
|
||||||
|
|
||||||
|
// We must always reset the handshake before a modded connection is established if
|
||||||
|
// we haven't done so already.
|
||||||
|
serverConn.getPlayer().sendLegacyForgeHandshakeResetPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always forward these messages during login
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
||||||
|
if (id == null) {
|
||||||
|
serverConn.getPlayer().getConnection().write(packet);
|
||||||
|
} else {
|
||||||
|
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id, packet.getData());
|
||||||
|
server.getEventManager().fire(event)
|
||||||
|
.thenAcceptAsync(pme -> {
|
||||||
|
if (pme.getResult().isAllowed()) {
|
||||||
|
serverConn.getPlayer().getConnection().write(packet);
|
||||||
|
}
|
||||||
|
}, serverConn.getConnection().eventLoop());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(TabCompleteResponse packet) {
|
||||||
|
playerSessionHandler.handleTabCompleteResponse(packet);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleGeneric(MinecraftPacket packet) {
|
public void handleGeneric(MinecraftPacket packet) {
|
||||||
if (!serverConn.getPlayer().isActive()) {
|
if (!serverConn.getPlayer().isActive()) {
|
||||||
@ -38,69 +127,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientPlaySessionHandler playerHandler =
|
if (serverConn.hasCompletedJoin()) {
|
||||||
(ClientPlaySessionHandler) serverConn.getPlayer().getConnection().getSessionHandler();
|
|
||||||
if (packet instanceof KeepAlive) {
|
|
||||||
// Forward onto the player
|
|
||||||
serverConn.setLastPingId(((KeepAlive) packet).getRandomId());
|
|
||||||
serverConn.getPlayer().getConnection().write(packet);
|
|
||||||
} else if (packet instanceof Disconnect) {
|
|
||||||
Disconnect original = (Disconnect) packet;
|
|
||||||
serverConn.disconnect();
|
|
||||||
serverConn.getPlayer().handleConnectionException(serverConn.getServer(), original);
|
|
||||||
} else if (packet instanceof JoinGame) {
|
|
||||||
playerHandler.handleBackendJoinGame((JoinGame) 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;
|
|
||||||
}
|
|
||||||
serverConn.getPlayer().getConnection().write(packet);
|
|
||||||
} else if (packet instanceof PluginMessage) {
|
|
||||||
PluginMessage pm = (PluginMessage) packet;
|
|
||||||
if (!canForwardPluginMessage(pm)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PluginMessageUtil.isMCBrand(pm)) {
|
|
||||||
serverConn.getPlayer().getConnection().write(PluginMessageUtil.rewriteMCBrand(pm));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serverConn.hasCompletedJoin() && pm.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) {
|
|
||||||
if (!serverConn.isLegacyForge()) {
|
|
||||||
serverConn.setLegacyForge(true);
|
|
||||||
|
|
||||||
// We must always reset the handshake before a modded connection is established if
|
|
||||||
// we haven't done so already.
|
|
||||||
serverConn.getPlayer().sendLegacyForgeHandshakeResetPacket();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always forward these messages during login
|
|
||||||
serverConn.getPlayer().getConnection().write(pm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(pm.getChannel());
|
|
||||||
if (id == null) {
|
|
||||||
serverConn.getPlayer().getConnection().write(pm);
|
|
||||||
} else {
|
|
||||||
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id, pm.getData());
|
|
||||||
server.getEventManager().fire(event)
|
|
||||||
.thenAcceptAsync(pme -> {
|
|
||||||
if (pme.getResult().isAllowed()) {
|
|
||||||
serverConn.getPlayer().getConnection().write(pm);
|
|
||||||
}
|
|
||||||
}, serverConn.getConnection().eventLoop());
|
|
||||||
}
|
|
||||||
} else if (packet instanceof TabCompleteResponse) {
|
|
||||||
playerHandler.handleTabCompleteResponse((TabCompleteResponse) packet);
|
|
||||||
} else if (serverConn.hasCompletedJoin()) {
|
|
||||||
// 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.
|
||||||
serverConn.getPlayer().getConnection().write(packet);
|
serverConn.getPlayer().getConnection().write(packet);
|
||||||
}
|
}
|
||||||
|
@ -36,17 +36,18 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleGeneric(MinecraftPacket packet) {
|
public boolean handle(EncryptionRequest packet) {
|
||||||
if (packet instanceof EncryptionRequest) {
|
|
||||||
throw new IllegalStateException("Backend server is online-mode!");
|
throw new IllegalStateException("Backend server is online-mode!");
|
||||||
} else if (packet instanceof LoginPluginMessage) {
|
}
|
||||||
LoginPluginMessage message = (LoginPluginMessage) packet;
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(LoginPluginMessage packet) {
|
||||||
VelocityConfiguration configuration = server.getConfiguration();
|
VelocityConfiguration configuration = server.getConfiguration();
|
||||||
if (configuration.getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN &&
|
if (configuration.getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && packet.getChannel()
|
||||||
message.getChannel().equals(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL)) {
|
.equals(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL)) {
|
||||||
LoginPluginResponse response = new LoginPluginResponse();
|
LoginPluginResponse response = new LoginPluginResponse();
|
||||||
response.setSuccess(true);
|
response.setSuccess(true);
|
||||||
response.setId(message.getId());
|
response.setId(packet.getId());
|
||||||
response.setData(createForwardingData(configuration.getForwardingSecret(),
|
response.setData(createForwardingData(configuration.getForwardingSecret(),
|
||||||
serverConn.getPlayer().getRemoteAddress().getHostString(),
|
serverConn.getPlayer().getRemoteAddress().getHostString(),
|
||||||
serverConn.getPlayer().getProfile()));
|
serverConn.getPlayer().getProfile()));
|
||||||
@ -56,24 +57,35 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
// Don't understand
|
// Don't understand
|
||||||
LoginPluginResponse response = new LoginPluginResponse();
|
LoginPluginResponse response = new LoginPluginResponse();
|
||||||
response.setSuccess(false);
|
response.setSuccess(false);
|
||||||
response.setId(message.getId());
|
response.setId(packet.getId());
|
||||||
response.setData(Unpooled.EMPTY_BUFFER);
|
response.setData(Unpooled.EMPTY_BUFFER);
|
||||||
serverConn.getConnection().write(response);
|
serverConn.getConnection().write(response);
|
||||||
}
|
}
|
||||||
} else if (packet instanceof Disconnect) {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(Disconnect packet) {
|
||||||
Disconnect disconnect = (Disconnect) packet;
|
Disconnect disconnect = (Disconnect) packet;
|
||||||
// Do we have an outstanding notification? If so, fulfill it.
|
// Do we have an outstanding notification? If so, fulfill it.
|
||||||
doNotify(ConnectionRequestResults.forDisconnect(disconnect));
|
doNotify(ConnectionRequestResults.forDisconnect(disconnect));
|
||||||
serverConn.disconnect();
|
serverConn.disconnect();
|
||||||
} else if (packet instanceof SetCompression) {
|
return true;
|
||||||
SetCompression sc = (SetCompression) packet;
|
}
|
||||||
serverConn.getConnection().setCompressionThreshold(sc.getThreshold());
|
|
||||||
} else if (packet instanceof ServerLoginSuccess) {
|
@Override
|
||||||
|
public boolean handle(SetCompression packet) {
|
||||||
|
serverConn.getConnection().setCompressionThreshold(packet.getThreshold());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(ServerLoginSuccess packet) {
|
||||||
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && !informationForwarded) {
|
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && !informationForwarded) {
|
||||||
doNotify(ConnectionRequestResults.forDisconnect(
|
doNotify(ConnectionRequestResults.forDisconnect(
|
||||||
TextComponent.of("Your server did not send a forwarding request to the proxy. Is it set up correctly?")));
|
TextComponent.of("Your server did not send a forwarding request to the proxy. Is it set up correctly?")));
|
||||||
serverConn.disconnect();
|
serverConn.disconnect();
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The player has been logged on to the backend server.
|
// The player has been logged on to the backend server.
|
||||||
@ -94,7 +106,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
doNotify(ConnectionRequestResults.SUCCESSFUL);
|
doNotify(ConnectionRequestResults.SUCCESSFUL);
|
||||||
serverConn.getConnection().setSessionHandler(new BackendPlaySessionHandler(server, serverConn));
|
serverConn.getConnection().setSessionHandler(new BackendPlaySessionHandler(server, serverConn));
|
||||||
serverConn.getPlayer().setConnectedServer(serverConn);
|
serverConn.getPlayer().setConnectedServer(serverConn);
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -48,6 +48,128 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
player.getConnection().write(register);
|
player.getConnection().write(register);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(KeepAlive packet) {
|
||||||
|
VelocityServerConnection serverConnection = player.getConnectedServer();
|
||||||
|
if (serverConnection != null && packet.getRandomId() == serverConnection.getLastPingId()) {
|
||||||
|
player.setPing(System.currentTimeMillis() - serverConnection.getLastPingSent());
|
||||||
|
serverConnection.getConnection().write(packet);
|
||||||
|
serverConnection.resetLastPingId();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(ClientSettings packet) {
|
||||||
|
player.setPlayerSettings(packet);
|
||||||
|
return false; // will forward onto the handleGeneric below, which will write the packet to the remote server
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(Chat packet) {
|
||||||
|
String msg = packet.getMessage();
|
||||||
|
if (msg.startsWith("/")) {
|
||||||
|
try {
|
||||||
|
if (!server.getCommandManager().execute(player, msg.substring(1))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.info("Exception occurred while running command for {}", player.getProfile().getName(), e);
|
||||||
|
player.sendMessage(TextComponent.of("An error occurred while running this command.", TextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VelocityServerConnection serverConnection = player.getConnectedServer();
|
||||||
|
if (serverConnection == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
PlayerChatEvent event = new PlayerChatEvent(player, msg);
|
||||||
|
server.getEventManager().fire(event)
|
||||||
|
.thenAcceptAsync(pme -> {
|
||||||
|
if (pme.getResult().equals(PlayerChatEvent.ChatResult.allowed())){
|
||||||
|
serverConnection.getConnection().write(packet);
|
||||||
|
} else if (pme.getResult().isAllowed() && pme.getResult().getMessage().isPresent()){
|
||||||
|
serverConnection.getConnection().write(Chat.createServerbound(pme.getResult().getMessage().get()));
|
||||||
|
}
|
||||||
|
}, serverConnection.getConnection().eventLoop());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(TabCompleteRequest packet) {
|
||||||
|
// Record the request so that the outstanding request can be augmented later.
|
||||||
|
if (!packet.isAssumeCommand() && packet.getCommand().startsWith("/")) {
|
||||||
|
int spacePos = packet.getCommand().indexOf(' ');
|
||||||
|
if (spacePos > 0) {
|
||||||
|
String cmd = packet.getCommand().substring(1, spacePos);
|
||||||
|
if (server.getCommandManager().hasCommand(cmd)) {
|
||||||
|
Optional<List<String>> suggestions = server.getCommandManager().offerSuggestions(player, packet.getCommand().substring(1));
|
||||||
|
if (suggestions.isPresent()) {
|
||||||
|
TabCompleteResponse resp = new TabCompleteResponse();
|
||||||
|
resp.getOffers().addAll(suggestions.get());
|
||||||
|
player.getConnection().write(resp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outstandingTabComplete = packet;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(PluginMessage packet) {
|
||||||
|
if (PluginMessageUtil.isMCRegister(packet)) {
|
||||||
|
List<String> actuallyRegistered = new ArrayList<>();
|
||||||
|
List<String> channels = PluginMessageUtil.getChannels(packet);
|
||||||
|
for (String channel : channels) {
|
||||||
|
if (clientPluginMsgChannels.size() >= MAX_PLUGIN_CHANNELS &&
|
||||||
|
!clientPluginMsgChannels.contains(channel)) {
|
||||||
|
throw new IllegalStateException("Too many plugin message channels registered");
|
||||||
|
}
|
||||||
|
if (clientPluginMsgChannels.add(channel)) {
|
||||||
|
actuallyRegistered.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actuallyRegistered.size() > 0) {
|
||||||
|
PluginMessage newRegisterPacket = PluginMessageUtil.constructChannelsPacket(player.getProtocolVersion(), actuallyRegistered);
|
||||||
|
player.getConnectedServer().getConnection().write(newRegisterPacket);
|
||||||
|
}
|
||||||
|
} else if (PluginMessageUtil.isMCUnregister(packet)) {
|
||||||
|
List<String> channels = PluginMessageUtil.getChannels(packet);
|
||||||
|
clientPluginMsgChannels.removeAll(channels);
|
||||||
|
player.getConnectedServer().getConnection().write(packet);
|
||||||
|
} else if (PluginMessageUtil.isMCBrand(packet)) {
|
||||||
|
player.getConnectedServer().getConnection().write(PluginMessageUtil.rewriteMCBrand(packet));
|
||||||
|
} else if (player.getConnectedServer().isLegacyForge() && !player.getConnectedServer().hasCompletedJoin()) {
|
||||||
|
if (packet.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) {
|
||||||
|
// Always forward the FML handshake to the remote server.
|
||||||
|
player.getConnectedServer().getConnection().write(packet);
|
||||||
|
} else {
|
||||||
|
// The client is trying to send messages too early. This is primarily caused by mods, but it's further
|
||||||
|
// aggravated by Velocity. To work around these issues, we will queue any non-FML handshake messages to
|
||||||
|
// be sent once the JoinGame packet has been received by the proxy.
|
||||||
|
loginPluginMessages.add(packet);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
||||||
|
if (id == null) {
|
||||||
|
player.getConnectedServer().getConnection().write(packet);
|
||||||
|
} else {
|
||||||
|
PluginMessageEvent event = new PluginMessageEvent(player, player.getConnectedServer(), id, packet.getData());
|
||||||
|
server.getEventManager().fire(event)
|
||||||
|
.thenAcceptAsync(pme -> {
|
||||||
|
if (pme.getResult().isAllowed()) {
|
||||||
|
player.getConnectedServer().getConnection().write(packet);
|
||||||
|
}
|
||||||
|
}, player.getConnectedServer().getConnection().eventLoop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleGeneric(MinecraftPacket packet) {
|
public void handleGeneric(MinecraftPacket packet) {
|
||||||
VelocityServerConnection serverConnection = player.getConnectedServer();
|
VelocityServerConnection serverConnection = player.getConnectedServer();
|
||||||
@ -56,65 +178,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet instanceof KeepAlive) {
|
|
||||||
KeepAlive keepAlive = (KeepAlive) packet;
|
|
||||||
if (keepAlive.getRandomId() != serverConnection.getLastPingId()) {
|
|
||||||
// The last keep alive we got was probably from a different server. Let's ignore it, and hope the next
|
|
||||||
// ping is alright.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
player.setPing(System.currentTimeMillis() - serverConnection.getLastPingSent());
|
|
||||||
serverConnection.getConnection().write(packet);
|
|
||||||
serverConnection.resetLastPingId();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet instanceof ClientSettings) {
|
|
||||||
player.setPlayerSettings((ClientSettings) packet);
|
|
||||||
// forward it on
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet instanceof Chat) {
|
|
||||||
// Try to handle any commands on the proxy. If that fails, send it onto the client.
|
|
||||||
Chat chat = (Chat) packet;
|
|
||||||
String msg = ((Chat) packet).getMessage();
|
|
||||||
if (msg.startsWith("/")) {
|
|
||||||
try {
|
|
||||||
if (!server.getCommandManager().execute(player, msg.substring(1))) {
|
|
||||||
player.getConnectedServer().getConnection().write(chat);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.info("Exception occurred while running command for {}", player.getProfile().getName(), e);
|
|
||||||
player.sendMessage(TextComponent.of("An error occurred while running this command.", TextColor.RED));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PlayerChatEvent event = new PlayerChatEvent(player, msg);
|
|
||||||
server.getEventManager().fire(event)
|
|
||||||
.thenAcceptAsync(pme -> {
|
|
||||||
if (pme.getResult().equals(PlayerChatEvent.ChatResult.allowed())){
|
|
||||||
serverConnection.getConnection().write(chat);
|
|
||||||
} else if (pme.getResult().isAllowed() && pme.getResult().getMessage().isPresent()){
|
|
||||||
serverConnection.getConnection().write(Chat.createServerbound(pme.getResult().getMessage().get()));
|
|
||||||
}
|
|
||||||
}, serverConnection.getConnection().eventLoop());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet instanceof TabCompleteRequest) {
|
|
||||||
// Record the request so that the outstanding request can be augmented later.
|
|
||||||
outstandingTabComplete = (TabCompleteRequest) packet;
|
|
||||||
serverConnection.getConnection().write(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet instanceof PluginMessage) {
|
|
||||||
handleClientPluginMessage((PluginMessage) packet);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
||||||
if (serverConnection.hasCompletedJoin()) {
|
if (serverConnection.hasCompletedJoin()) {
|
||||||
|
logger.info("Will write {}", packet);
|
||||||
serverConnection.getConnection().write(packet);
|
serverConnection.getConnection().write(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,62 +311,15 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
return serverBossBars;
|
return serverBossBars;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleClientPluginMessage(PluginMessage packet) {
|
|
||||||
if (PluginMessageUtil.isMCRegister(packet)) {
|
|
||||||
List<String> actuallyRegistered = new ArrayList<>();
|
|
||||||
List<String> channels = PluginMessageUtil.getChannels(packet);
|
|
||||||
for (String channel : channels) {
|
|
||||||
if (clientPluginMsgChannels.size() >= MAX_PLUGIN_CHANNELS &&
|
|
||||||
!clientPluginMsgChannels.contains(channel)) {
|
|
||||||
throw new IllegalStateException("Too many plugin message channels registered");
|
|
||||||
}
|
|
||||||
if (clientPluginMsgChannels.add(channel)) {
|
|
||||||
actuallyRegistered.add(channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actuallyRegistered.size() > 0) {
|
|
||||||
PluginMessage newRegisterPacket = PluginMessageUtil.constructChannelsPacket(player.getProtocolVersion(), actuallyRegistered);
|
|
||||||
player.getConnectedServer().getConnection().write(newRegisterPacket);
|
|
||||||
}
|
|
||||||
} else if (PluginMessageUtil.isMCUnregister(packet)) {
|
|
||||||
List<String> channels = PluginMessageUtil.getChannels(packet);
|
|
||||||
clientPluginMsgChannels.removeAll(channels);
|
|
||||||
player.getConnectedServer().getConnection().write(packet);
|
|
||||||
} else if (PluginMessageUtil.isMCBrand(packet)) {
|
|
||||||
player.getConnectedServer().getConnection().write(PluginMessageUtil.rewriteMCBrand(packet));
|
|
||||||
} else if (player.getConnectedServer().isLegacyForge() && !player.getConnectedServer().hasCompletedJoin()) {
|
|
||||||
if (packet.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) {
|
|
||||||
// Always forward the FML handshake to the remote server.
|
|
||||||
player.getConnectedServer().getConnection().write(packet);
|
|
||||||
} else {
|
|
||||||
// The client is trying to send messages too early. This is primarily caused by mods, but it's further
|
|
||||||
// aggravated by Velocity. To work around these issues, we will queue any non-FML handshake messages to
|
|
||||||
// be sent once the JoinGame packet has been received by the proxy.
|
|
||||||
loginPluginMessages.add(packet);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
|
||||||
if (id == null) {
|
|
||||||
player.getConnectedServer().getConnection().write(packet);
|
|
||||||
} else {
|
|
||||||
PluginMessageEvent event = new PluginMessageEvent(player, player.getConnectedServer(), id, packet.getData());
|
|
||||||
server.getEventManager().fire(event)
|
|
||||||
.thenAcceptAsync(pme -> {
|
|
||||||
if (pme.getResult().isAllowed()) {
|
|
||||||
player.getConnectedServer().getConnection().write(packet);
|
|
||||||
}
|
|
||||||
}, player.getConnectedServer().getConnection().eventLoop());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getClientPluginMsgChannels() {
|
public Set<String> getClientPluginMsgChannels() {
|
||||||
return clientPluginMsgChannels;
|
return clientPluginMsgChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleTabCompleteResponse(TabCompleteResponse response) {
|
public void handleTabCompleteResponse(TabCompleteResponse response) {
|
||||||
|
logger.info("Got {}", response);
|
||||||
|
logger.info("Request {}", outstandingTabComplete);
|
||||||
if (outstandingTabComplete != null) {
|
if (outstandingTabComplete != null) {
|
||||||
|
logger.info("HANDLING");
|
||||||
if (!outstandingTabComplete.isAssumeCommand()) {
|
if (!outstandingTabComplete.isAssumeCommand()) {
|
||||||
String command = outstandingTabComplete.getCommand().substring(1);
|
String command = outstandingTabComplete.getCommand().substring(1);
|
||||||
try {
|
try {
|
||||||
|
@ -117,7 +117,8 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleUnknown(ByteBuf buf) {
|
public void handleUnknown(ByteBuf buf) {
|
||||||
throw new IllegalStateException("Unknown data " + ByteBufUtil.hexDump(buf));
|
// what even is going on?
|
||||||
|
connection.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LegacyInboundConnection implements InboundConnection {
|
private static class LegacyInboundConnection implements InboundConnection {
|
||||||
|
@ -59,23 +59,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleGeneric(MinecraftPacket packet) {
|
public boolean handle(ServerLogin packet) {
|
||||||
if (packet instanceof LoginPluginResponse) {
|
this.login = packet;
|
||||||
LoginPluginResponse lpr = (LoginPluginResponse) packet;
|
|
||||||
if (lpr.getId() == playerInfoId) {
|
|
||||||
if (lpr.isSuccess()) {
|
|
||||||
// Uh oh, someone's trying to run Velocity behind Velocity. We don't want that happening.
|
|
||||||
inbound.closeWith(Disconnect.create(
|
|
||||||
TextComponent.of("Running Velocity behind Velocity isn't supported.", TextColor.RED)
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
// Proceed with the regular login process.
|
|
||||||
beginPreLogin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (packet instanceof ServerLogin) {
|
|
||||||
this.login = (ServerLogin) packet;
|
|
||||||
|
|
||||||
if (inbound.getProtocolVersion() >= ProtocolConstants.MINECRAFT_1_13) {
|
if (inbound.getProtocolVersion() >= ProtocolConstants.MINECRAFT_1_13) {
|
||||||
LoginPluginMessage message = new LoginPluginMessage();
|
LoginPluginMessage message = new LoginPluginMessage();
|
||||||
playerInfoId = ThreadLocalRandom.current().nextInt();
|
playerInfoId = ThreadLocalRandom.current().nextInt();
|
||||||
@ -86,7 +71,27 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
} else {
|
} else {
|
||||||
beginPreLogin();
|
beginPreLogin();
|
||||||
}
|
}
|
||||||
} else if (packet instanceof EncryptionResponse) {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(LoginPluginResponse packet) {
|
||||||
|
if (packet.getId() == playerInfoId) {
|
||||||
|
if (packet.isSuccess()) {
|
||||||
|
// Uh oh, someone's trying to run Velocity behind Velocity. We don't want that happening.
|
||||||
|
inbound.closeWith(Disconnect.create(
|
||||||
|
TextComponent.of("Running Velocity behind Velocity isn't supported.", TextColor.RED)
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
// Proceed with the regular login process.
|
||||||
|
beginPreLogin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(EncryptionResponse packet) {
|
||||||
try {
|
try {
|
||||||
KeyPair serverKeyPair = server.getServerKeyPair();
|
KeyPair serverKeyPair = server.getServerKeyPair();
|
||||||
EncryptionResponse response = (EncryptionResponse) packet;
|
EncryptionResponse response = (EncryptionResponse) packet;
|
||||||
@ -141,7 +146,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beginPreLogin() {
|
private void beginPreLogin() {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.velocitypowered.proxy.connection.client;
|
package com.velocitypowered.proxy.connection.client;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||||
import com.velocitypowered.api.proxy.InboundConnection;
|
import com.velocitypowered.api.proxy.InboundConnection;
|
||||||
@ -9,13 +8,11 @@ import com.velocitypowered.proxy.VelocityServer;
|
|||||||
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolConstants;
|
import com.velocitypowered.proxy.protocol.ProtocolConstants;
|
||||||
import com.velocitypowered.proxy.protocol.packet.StatusPing;
|
import com.velocitypowered.proxy.protocol.packet.StatusPing;
|
||||||
import com.velocitypowered.proxy.protocol.packet.StatusRequest;
|
import com.velocitypowered.proxy.protocol.packet.StatusRequest;
|
||||||
import com.velocitypowered.proxy.protocol.packet.StatusResponse;
|
import com.velocitypowered.proxy.protocol.packet.StatusResponse;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
|
||||||
|
|
||||||
public class StatusSessionHandler implements MinecraftSessionHandler {
|
public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||||
private final VelocityServer server;
|
private final VelocityServer server;
|
||||||
@ -29,19 +26,15 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleGeneric(MinecraftPacket packet) {
|
public boolean handle(StatusPing packet) {
|
||||||
Preconditions.checkArgument(packet instanceof StatusPing || packet instanceof StatusRequest,
|
|
||||||
"Unrecognized packet type " + packet.getClass().getName());
|
|
||||||
|
|
||||||
if (packet instanceof StatusPing) {
|
|
||||||
// Just send back the client's packet, no processing to do here.
|
|
||||||
connection.closeWith(packet);
|
connection.closeWith(packet);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(StatusRequest packet) {
|
||||||
VelocityConfiguration configuration = server.getConfiguration();
|
VelocityConfiguration configuration = server.getConfiguration();
|
||||||
|
|
||||||
// Status request
|
|
||||||
int shownVersion = ProtocolConstants.isSupported(connection.getProtocolVersion()) ? connection.getProtocolVersion() :
|
int shownVersion = ProtocolConstants.isSupported(connection.getProtocolVersion()) ? connection.getProtocolVersion() :
|
||||||
ProtocolConstants.MAXIMUM_GENERIC_VERSION;
|
ProtocolConstants.MAXIMUM_GENERIC_VERSION;
|
||||||
ServerPing initialPing = new ServerPing(
|
ServerPing initialPing = new ServerPing(
|
||||||
@ -59,10 +52,12 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
|||||||
response.setStatus(VelocityServer.GSON.toJson(event.getPing()));
|
response.setStatus(VelocityServer.GSON.toJson(event.getPing()));
|
||||||
connection.write(response);
|
connection.write(response);
|
||||||
}, connection.eventLoop());
|
}, connection.eventLoop());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleUnknown(ByteBuf buf) {
|
public void handleUnknown(ByteBuf buf) {
|
||||||
throw new IllegalStateException("Unknown data " + ByteBufUtil.hexDump(buf));
|
// what even is going on?
|
||||||
|
connection.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
package com.velocitypowered.proxy.server.ping;
|
package com.velocitypowered.proxy.server.ping;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
import com.velocitypowered.api.proxy.server.ServerPing;
|
import com.velocitypowered.api.proxy.server.ServerPing;
|
||||||
import com.velocitypowered.proxy.VelocityServer;
|
import com.velocitypowered.proxy.VelocityServer;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolConstants;
|
import com.velocitypowered.proxy.protocol.ProtocolConstants;
|
||||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
import com.velocitypowered.proxy.protocol.packet.Handshake;
|
import com.velocitypowered.proxy.protocol.packet.Handshake;
|
||||||
@ -42,15 +40,14 @@ public class PingSessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleGeneric(MinecraftPacket packet) {
|
public boolean handle(StatusResponse packet) {
|
||||||
Preconditions.checkState(packet instanceof StatusResponse, "Did not get status response back from connection");
|
|
||||||
|
|
||||||
// All good!
|
// All good!
|
||||||
completed = true;
|
completed = true;
|
||||||
connection.close();
|
connection.close();
|
||||||
|
|
||||||
ServerPing ping = VelocityServer.GSON.fromJson(((StatusResponse) packet).getStatus(), ServerPing.class);
|
ServerPing ping = VelocityServer.GSON.fromJson(((StatusResponse) packet).getStatus(), ServerPing.class);
|
||||||
result.complete(ping);
|
result.complete(ping);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren