1
0
mirror of https://github.com/GeyserMC/Floodgate.git synced 2026-01-04 15:31:48 +00:00

Stopped using disconnect and (Bungee's) handshake event

Instead we're listening for the actual channel to close.
This commit is contained in:
Tim203
2021-01-18 01:34:19 +01:00
parent 61739fbd58
commit 3eb607772d
27 changed files with 591 additions and 289 deletions

View File

@@ -47,6 +47,16 @@ public interface InjectorAddon {
*/
void onLoginDone(Channel channel);
/**
* Called when the channel has been closed. Note that this method will be called for every
* closed connection (if it is injected), so it'll also run this method for closed connections
* between a server and the proxy (when Floodgate is running on a proxy).
*
* @param channel the channel that the injecor injected
*/
default void onChannelClosed(Channel channel) {
}
/**
* Called when Floodgate is removing the injection from the server. The addon should remove his
* traces otherwise it is likely that an error will popup after the server is injected again.

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.addon.data;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.util.Utils;
public class BungeeDataAddon implements InjectorAddon {
@Inject private FloodgateHandshakeHandler handshakeHandler;
@Inject private ProxyFloodgateConfig config;
@Inject private ProxyFloodgateApi api;
@Inject private FloodgateLogger logger;
@Inject
@Named("packetHandler")
private String packetHandler;
@Inject
@Named("packetEncoder")
private String packetEncoder;
@Inject
@Named("kickMessageAttribute")
private AttributeKey<String> kickMessageAttribute;
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
@Override
public void onInject(Channel channel, boolean toServer) {
if (toServer) {
channel.pipeline().addAfter(
packetEncoder, "floodgate_data_handler",
new BungeeServerDataHandler(config, api, playerAttribute)
);
return;
}
channel.pipeline().addBefore(
packetHandler, "floodgate_data_handler",
new BungeeProxyDataHandler(config, handshakeHandler, kickMessageAttribute)
);
}
@Override
public void onLoginDone(Channel channel) {
onRemoveInject(channel);
}
@Override
public void onChannelClosed(Channel channel) {
FloodgatePlayer player = channel.attr(playerAttribute).get();
if (player != null && api.removePlayer(player)) {
api.removeEncryptedData(player.getCorrectUniqueId());
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getCorrectUsername());
}
}
@Override
public void onRemoveInject(Channel channel) {
Utils.removeHandler(channel.pipeline(), "floodgate_data_handler");
}
@Override
public boolean shouldInject() {
return true;
}
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.addon.data;
import static com.google.common.base.Preconditions.checkNotNull;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.PacketWrapper;
import net.md_5.bungee.protocol.packet.Handshake;
import org.geysermc.floodgate.api.handshake.HandshakeData;
import org.geysermc.floodgate.api.player.PropertyKey;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.ResultType;
import org.geysermc.floodgate.util.ReflectionUtils;
@SuppressWarnings("ConstantConditions")
@RequiredArgsConstructor
public class BungeeProxyDataHandler extends ChannelInboundHandlerAdapter {
private static final Field HANDLER;
private static final Field CHANNEL_WRAPPER;
static {
HANDLER = ReflectionUtils.getField(HandlerBoss.class, "handler");
checkNotNull(HANDLER, "handler field cannot be null");
CHANNEL_WRAPPER =
ReflectionUtils.getFieldOfType(InitialHandler.class, ChannelWrapper.class);
checkNotNull(CHANNEL_WRAPPER, "ChannelWrapper field cannot be null");
}
private final ProxyFloodgateConfig config;
private final FloodgateHandshakeHandler handler;
private final AttributeKey<String> kickMessageAttribute;
private boolean done;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ReferenceCountUtil.retain(msg);
if (done || !(msg instanceof PacketWrapper)) {
ctx.fireChannelRead(msg);
return;
}
DefinedPacket packet = ((PacketWrapper) msg).packet;
// we're only interested in the Handshake packet
if (packet instanceof Handshake) {
handleHandshake(ctx, (Handshake) packet);
done = true;
}
ctx.fireChannelRead(msg);
}
private void handleHandshake(ChannelHandlerContext ctx, Handshake packet) {
String data = packet.getHost();
HandshakeResult result = handler.handle(ctx.channel(), data);
HandshakeData handshakeData = result.getHandshakeData();
// we'll change the IP address from the proxy to the IP of the Bedrock client very early on
// so that almost every plugin will use the IP of the Bedrock client
if (result.getFloodgatePlayer() != null) {
HandlerBoss handlerBoss = ctx.pipeline().get(HandlerBoss.class);
// InitialHandler extends PacketHandler and implements PendingConnection
InitialHandler connection = ReflectionUtils.getCastedValue(handlerBoss, HANDLER);
ChannelWrapper channelWrapper =
ReflectionUtils.getCastedValue(connection, CHANNEL_WRAPPER);
InetSocketAddress address =
result.getFloodgatePlayer().getProperty(PropertyKey.SOCKET_ADDRESS);
channelWrapper.setRemoteAddress(address);
}
if (handshakeData.getDisconnectReason() != null) {
ctx.channel().attr(kickMessageAttribute).set(handshakeData.getDisconnectReason());
return;
}
if (result.getResultType() == ResultType.EXCEPTION) {
ctx.channel().attr(kickMessageAttribute).set(
config.getDisconnect().getInvalidKey());
}
if (result.getResultType() == ResultType.INVALID_DATA_LENGTH) {
ctx.channel().attr(kickMessageAttribute)
.set(config.getDisconnect().getInvalidArgumentsLength());
}
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.addon.data;
import static com.google.common.base.Preconditions.checkNotNull;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil;
import java.lang.reflect.Field;
import java.util.List;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.ServerConnector;
import net.md_5.bungee.UserConnection;
import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.protocol.packet.Handshake;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.util.ReflectionUtils;
@SuppressWarnings("ConstantConditions")
@RequiredArgsConstructor
public class BungeeServerDataHandler extends MessageToMessageEncoder<Object> {
private static final Field HANDLER;
private static final Field USER_CONNECTION;
private static final Field CHANNEL_WRAPPER;
static {
HANDLER = ReflectionUtils.getField(HandlerBoss.class, "handler");
checkNotNull(HANDLER, "handler field cannot be null");
USER_CONNECTION = ReflectionUtils.getField(ServerConnector.class, "user");
checkNotNull(USER_CONNECTION, "user field cannot be null");
CHANNEL_WRAPPER =
ReflectionUtils.getFieldOfType(UserConnection.class, ChannelWrapper.class);
checkNotNull(CHANNEL_WRAPPER, "ChannelWrapper field cannot be null");
}
private final ProxyFloodgateConfig config;
private final ProxyFloodgateApi api;
private final AttributeKey<FloodgatePlayer> playerAttribute;
private boolean done;
@Override
protected void encode(ChannelHandlerContext ctx, Object packet, List<Object> out) {
ReferenceCountUtil.retain(packet);
if (done) {
out.add(packet);
return;
}
// passes the information through to the connecting server if enabled
if (!(packet instanceof Handshake) || !config.isSendFloodgateData()) {
done = true;
out.add(packet);
return;
}
// get the Proxy <-> Player channel from the Proxy <-> Server channel
HandlerBoss handlerBoss = ctx.pipeline().get(HandlerBoss.class);
ServerConnector connector = ReflectionUtils.getCastedValue(handlerBoss, HANDLER);
UserConnection connection = ReflectionUtils.getCastedValue(connector, USER_CONNECTION);
ChannelWrapper wrapper = ReflectionUtils.getCastedValue(connection, CHANNEL_WRAPPER);
FloodgatePlayer player = wrapper.getHandle().attr(playerAttribute).get();
if (player != null) {
String encryptedData = api.getEncryptedData(player.getCorrectUniqueId());
Handshake handshake = (Handshake) packet;
String address = handshake.getHost();
// our data goes before all the other data
int addressFinished = address.indexOf('\0');
String originalAddress = address.substring(0, addressFinished);
String remaining = address.substring(addressFinished);
handshake.setHost(originalAddress + '\0' + encryptedData + remaining);
// Bungeecord will add his data after our data
}
done = true;
out.add(packet);
}
}

View File

@@ -1,174 +0,0 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.handler;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.geysermc.floodgate.player.FloodgateHandshakeHandler.ResultType;
import com.google.inject.Inject;
import io.netty.channel.Channel;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PreLoginEvent;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.protocol.packet.Handshake;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.handshake.HandshakeData;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.api.player.PropertyKey;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
import org.geysermc.floodgate.util.BedrockData;
import org.geysermc.floodgate.util.ReflectionUtils;
public final class BungeeDataHandler {
private static final Field EXTRA_HANDSHAKE_DATA;
private static final Field PLAYER_NAME;
private static final Field PLAYER_CHANNEL_WRAPPER;
private static final Field PLAYER_CHANNEL;
private static final Field PLAYER_REMOTE_ADDRESS;
private static final Field CACHED_HANDSHAKE_PACKET;
static {
Class<?> initialHandler = ReflectionUtils.getPrefixedClass("connection.InitialHandler");
EXTRA_HANDSHAKE_DATA = ReflectionUtils.getField(initialHandler, "extraDataInHandshake");
checkNotNull(EXTRA_HANDSHAKE_DATA, "extraDataInHandshake field cannot be null");
PLAYER_NAME = ReflectionUtils.getField(initialHandler, "name");
checkNotNull(PLAYER_NAME, "Initial name field cannot be null");
Class<?> channelWrapper = ReflectionUtils.getPrefixedClass("netty.ChannelWrapper");
PLAYER_CHANNEL_WRAPPER = ReflectionUtils.getFieldOfType(initialHandler, channelWrapper);
checkNotNull(PLAYER_CHANNEL_WRAPPER, "ChannelWrapper field cannot be null");
PLAYER_CHANNEL = ReflectionUtils.getFieldOfType(channelWrapper, Channel.class);
checkNotNull(PLAYER_CHANNEL, "Channel field cannot be null");
PLAYER_REMOTE_ADDRESS = ReflectionUtils.getFieldOfType(channelWrapper, SocketAddress.class);
checkNotNull(PLAYER_REMOTE_ADDRESS, "Remote address field cannot be null");
Class<?> handshakePacket = ReflectionUtils.getPrefixedClass("protocol.packet.Handshake");
CACHED_HANDSHAKE_PACKET = ReflectionUtils.getFieldOfType(initialHandler, handshakePacket);
checkNotNull(CACHED_HANDSHAKE_PACKET, "Cached handshake packet field cannot be null");
}
@Inject private Plugin plugin;
@Inject private ProxyFloodgateConfig config;
@Inject private ProxyFloodgateApi api;
@Inject private FloodgateHandshakeHandler handler;
@Inject private FloodgateLogger logger;
public void handlePreLogin(PreLoginEvent event) {
event.registerIntent(plugin);
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
PendingConnection connection = event.getConnection();
String extraData = ReflectionUtils.getCastedValue(connection, EXTRA_HANDSHAKE_DATA);
Object channelWrapper = ReflectionUtils.getValue(connection, PLAYER_CHANNEL_WRAPPER);
Channel channel = ReflectionUtils.getCastedValue(channelWrapper, PLAYER_CHANNEL);
HandshakeResult result = handler.handle(channel, extraData);
HandshakeData handshakeData = result.getHandshakeData();
if (handshakeData.getDisconnectReason() != null) {
//noinspection ConstantConditions
channel.close(); // todo disconnect with message
return;
}
if (result.getResultType() == ResultType.EXCEPTION) {
event.setCancelReason(config.getDisconnect().getInvalidKey());
event.completeIntent(plugin);
return;
}
if (result.getResultType() == ResultType.INVALID_DATA_LENGTH) {
event.setCancelReason(TextComponent.fromLegacyText(String.format(
config.getDisconnect().getInvalidArgumentsLength(),
BedrockData.EXPECTED_LENGTH, result.getBedrockData().getDataLength()
)));
event.completeIntent(plugin);
return;
}
// only continue when SUCCESS
if (result.getResultType() != ResultType.SUCCESS) {
event.completeIntent(plugin);
return;
}
FloodgatePlayer player = result.getFloodgatePlayer();
connection.setOnlineMode(false);
connection.setUniqueId(player.getCorrectUniqueId());
ReflectionUtils.setValue(connection, PLAYER_NAME, player.getCorrectUsername());
SocketAddress remoteAddress =
ReflectionUtils.getCastedValue(channelWrapper, PLAYER_REMOTE_ADDRESS);
if (!(remoteAddress instanceof InetSocketAddress)) {
logger.info("Player {} doesn't use an InetSocketAddress, it uses {}. " +
"Ignoring the player, I guess.",
player.getUsername(), remoteAddress.getClass().getSimpleName()
);
event.setCancelled(true);
event.setCancelReason(
new TextComponent("remoteAddress is not an InetSocketAddress!"));
event.completeIntent(plugin);
return;
}
InetSocketAddress correctAddress = player.getProperty(PropertyKey.SOCKET_ADDRESS);
ReflectionUtils.setValue(channelWrapper, PLAYER_REMOTE_ADDRESS, correctAddress);
event.completeIntent(plugin);
});
}
public void handleServerConnect(ProxiedPlayer player) {
// Passes the information through to the connecting server if enabled
if (config.isSendFloodgateData() && api.isFloodgatePlayer(player.getUniqueId())) {
Handshake handshake = ReflectionUtils.getCastedValue(
player.getPendingConnection(), CACHED_HANDSHAKE_PACKET
);
// Ensures that only the hostname remains,
// this way it can't mess up the Floodgate data format
String initialHostname = handshake.getHost().split("\0")[0];
handshake.setHost(initialHostname + '\0' + api.getEncryptedData(player.getUniqueId()));
// Bungeecord will add his data after our data
}
}
}

View File

@@ -96,5 +96,9 @@ public final class BungeeInjector extends CommonPlatformInjector {
public void injectClient(Channel channel, boolean clientToProxy) {
injectAddonsCall(channel, !clientToProxy);
addInjectedClient(channel);
channel.closeFuture().addListener(listener -> {
channelClosedCall(channel);
removeInjectedClient(channel);
});
}
}

View File

@@ -25,32 +25,50 @@
package org.geysermc.floodgate.listener;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import java.lang.reflect.Field;
import java.util.UUID;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PreLoginEvent;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.event.ServerConnectedEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import net.md_5.bungee.netty.ChannelWrapper;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.api.player.PropertyKey;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.handler.BungeeDataHandler;
import org.geysermc.floodgate.player.FloodgatePlayerImpl;
import org.geysermc.floodgate.pluginmessage.BungeePluginMessageHandler;
import org.geysermc.floodgate.skin.SkinHandler;
import org.geysermc.floodgate.util.BungeeCommandUtil;
import org.geysermc.floodgate.util.LanguageManager;
import org.geysermc.floodgate.util.ReflectionUtils;
@SuppressWarnings("ConstantConditions")
public final class BungeeListener implements Listener {
private BungeeDataHandler dataHandler;
private static final Field CHANNEL_WRAPPER;
private static final Field PLAYER_NAME;
static {
CHANNEL_WRAPPER =
ReflectionUtils.getFieldOfType(InitialHandler.class, ChannelWrapper.class);
checkNotNull(CHANNEL_WRAPPER, "ChannelWrapper field cannot be null");
PLAYER_NAME = ReflectionUtils.getField(InitialHandler.class, "name");
checkNotNull(PLAYER_NAME, "Initial name field cannot be null");
}
@Inject private ProxyFloodgateApi api;
@Inject private LanguageManager languageManager;
@Inject private FloodgateLogger logger;
@@ -60,14 +78,12 @@ public final class BungeeListener implements Listener {
@Inject private SkinHandler skinHandler;
@Inject
public void init(Injector injector) {
dataHandler = injector.getInstance(BungeeDataHandler.class);
}
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
@EventHandler(priority = EventPriority.LOW)
public void onServerConnect(ServerConnectEvent event) {
dataHandler.handleServerConnect(event.getPlayer());
}
@Inject
@Named("kickMessageAttribute")
private AttributeKey<String> kickMessageAttribute;
@EventHandler
public void onServerConnected(ServerConnectedEvent event) {
@@ -89,15 +105,31 @@ public final class BungeeListener implements Listener {
}
}
@EventHandler(priority = EventPriority.LOW)
@EventHandler(priority = EventPriority.LOWEST)
public void onPreLogin(PreLoginEvent event) {
dataHandler.handlePreLogin(event);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPreLoginMonitor(PreLoginEvent event) {
// well, no reason to check if the player will be kicked anyway
if (event.isCancelled()) {
api.removePlayer(event.getConnection().getUniqueId(), true);
return;
}
PendingConnection connection = event.getConnection();
ChannelWrapper wrapper = ReflectionUtils.getCastedValue(connection, CHANNEL_WRAPPER);
Channel channel = wrapper.getHandle();
// check if the player has to be kicked
String kickReason = channel.attr(kickMessageAttribute).get();
if (kickReason != null) {
event.setCancelled(true);
event.setCancelReason(kickReason);
return;
}
FloodgatePlayer player = channel.attr(playerAttribute).get();
if (player != null) {
connection.setOnlineMode(false);
connection.setUniqueId(player.getCorrectUniqueId());
ReflectionUtils.setValue(connection, PLAYER_NAME, player.getCorrectUsername());
}
}
@@ -117,22 +149,8 @@ public final class BungeeListener implements Listener {
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onLoginMonitor(LoginEvent event) {
if (event.isCancelled()) {
api.removePlayer(event.getConnection().getUniqueId());
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerDisconnect(PlayerDisconnectEvent event) {
ProxiedPlayer player = event.getPlayer();
BungeeCommandUtil.AUDIENCE_CACHE.remove(player.getUniqueId()); //todo
if (api.removePlayer(player.getUniqueId()) != null) {
api.removeEncryptedData(player.getUniqueId());
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getName());
}
BungeeCommandUtil.AUDIENCE_CACHE.remove(event.getPlayer().getUniqueId()); //todo
}
}

View File

@@ -30,6 +30,7 @@ import com.google.inject.Singleton;
import com.google.inject.multibindings.ProvidesIntoSet;
import org.geysermc.floodgate.addon.AddonManagerAddon;
import org.geysermc.floodgate.addon.DebugAddon;
import org.geysermc.floodgate.addon.data.BungeeDataAddon;
import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.register.AddonRegister;
@@ -45,6 +46,12 @@ public final class BungeeAddonModule extends AbstractModule {
return new AddonManagerAddon();
}
@Singleton
@ProvidesIntoSet
public InjectorAddon dataAddon() {
return new BungeeDataAddon();
}
@Singleton
@ProvidesIntoSet
public InjectorAddon debugAddon() {

View File

@@ -75,10 +75,6 @@ public class BungeeUserAudience implements UserAudience, ForwardingAudience.Sing
@Override
public void sendMessage(@NonNull Identity source, @NonNull Component message,
@NonNull MessageType type) {
if (type != MessageType.CHAT) {
throw new IllegalStateException("Cannot send any other messages then chat messages");
}
this.source.sendMessage(GsonComponentSerializer.gson().serialize(message));
}

View File

@@ -65,15 +65,23 @@ public class HandshakeDataImpl implements HandshakeData {
this.rawSkin = rawSkin;
this.hostname = hostname;
String prefix = config.getUsernamePrefix();
int usernameLength = Math.min(bedrockData.getUsername().length(), 16 - prefix.length());
String javaUsername = prefix + bedrockData.getUsername().substring(0, usernameLength);
if (config.isReplaceSpaces()) {
javaUsername = javaUsername.replaceAll(" ", "_");
}
this.javaUsername = javaUsername;
String javaUsername = null;
UUID javaUniqueId = null;
this.javaUniqueId = Utils.getJavaUuid(bedrockData.getXuid());
if (bedrockData != null) {
String prefix = config.getUsernamePrefix();
int usernameLength = Math.min(bedrockData.getUsername().length(), 16 - prefix.length());
javaUsername = prefix + bedrockData.getUsername().substring(0, usernameLength);
if (config.isReplaceSpaces()) {
javaUsername = javaUsername.replaceAll(" ", "_");
}
javaUniqueId = Utils.getJavaUuid(bedrockData.getXuid());
}
this.javaUsername = javaUsername;
this.javaUniqueId = javaUniqueId;
}
@Override

View File

@@ -39,7 +39,7 @@ import org.geysermc.floodgate.util.Utils;
@RequiredArgsConstructor
public class SimpleFloodgateApi implements FloodgateApi {
private final Map<UUID, FloodgatePlayer> players = new HashMap<>();
public final Map<UUID, FloodgatePlayer> players = new HashMap<>();
private final PluginMessageHandler pluginMessageHandler;
@Override
@@ -146,7 +146,6 @@ public class SimpleFloodgateApi implements FloodgateApi {
* instance directly.
*/
public boolean removePlayer(FloodgatePlayer player) {
boolean removed = players.remove(player.getJavaUniqueId(), player);
return removed && player.getLinkedPlayer() != null;
return players.remove(player.getJavaUniqueId(), player);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.command;
import cloud.commandframework.Command;
import cloud.commandframework.CommandManager;
import cloud.commandframework.context.CommandContext;
import net.kyori.adventure.text.Component;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.platform.command.FloodgateCommand;
import org.geysermc.floodgate.player.UserAudience;
import org.geysermc.floodgate.util.Constants;
public class TestCommand implements FloodgateCommand {
@Override
public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) {
return commandManager.commandBuilder("floodgate-test")
.senderType(UserAudience.class)
.handler(this::execute)
.build();
}
@Override
public void execute(CommandContext<UserAudience> context) {
int players = ((SimpleFloodgateApi) FloodgateApi.getInstance()).players.size();
context.getSender().sendMessage(Component.text(players));
}
@Override
public boolean shouldRegister(FloodgateConfig config) {
return Constants.DEBUG_MODE;
}
}

View File

@@ -30,11 +30,15 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import lombok.AccessLevel;
import lombok.Getter;
import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.inject.PlatformInjector;
public abstract class CommonPlatformInjector implements PlatformInjector {
@Getter(AccessLevel.PROTECTED)
private final Set<Channel> injectedClients = new HashSet<>();
private final Map<Class<?>, InjectorAddon> addons = new HashMap<>();
protected boolean addInjectedClient(Channel channel) {
@@ -86,6 +90,20 @@ public abstract class CommonPlatformInjector implements PlatformInjector {
}
}
/**
* Method to loop throguh all the addons and call {@link InjectorAddon#onChannelClosed(Channel)}
* if {@link InjectorAddon#shouldInject()}
*
* @param channel the channel that was injected
*/
public void channelClosedCall(Channel channel) {
for (InjectorAddon addon : addons.values()) {
if (addon.shouldInject()) {
addon.onChannelClosed(channel);
}
}
}
/**
* Method to loop through all the addons and call {@link InjectorAddon#onRemoveInject(Channel)}
* if {@link InjectorAddon#shouldInject()}.

View File

@@ -29,6 +29,7 @@ import com.google.inject.AbstractModule;
import com.google.inject.Singleton;
import com.google.inject.multibindings.ProvidesIntoSet;
import org.geysermc.floodgate.command.LinkAccountCommand;
import org.geysermc.floodgate.command.TestCommand;
import org.geysermc.floodgate.command.UnlinkAccountCommand;
import org.geysermc.floodgate.platform.command.FloodgateCommand;
import org.geysermc.floodgate.register.CommandRegister;
@@ -50,4 +51,10 @@ public class CommandModule extends AbstractModule {
public FloodgateCommand unlinkAccountCommand() {
return new UnlinkAccountCommand();
}
@Singleton
@ProvidesIntoSet
public FloodgateCommand testCommand() {
return new TestCommand();
}
}

View File

@@ -149,6 +149,13 @@ public class CommonModule extends AbstractModule {
);
}
@Provides
@Singleton
@Named("kickMessageAttribute")
public AttributeKey<String> kickMessageAttribute() {
return AttributeKey.valueOf("floodgate-kick-message");
}
@Provides
@Singleton
@Named("playerAttribute")

View File

@@ -28,4 +28,6 @@ package org.geysermc.floodgate.util;
public final class Constants {
public static final String DATABASE_NAME_FORMAT = "^floodgate-[a-zA-Z0-9_]{0,16}-database.jar$";
public static final int LOGIN_SUCCESS_PACKET_ID = 2;
public static final boolean DEBUG_MODE = true;
}

View File

@@ -28,8 +28,11 @@ package org.geysermc.floodgate.addon.data;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.util.Utils;
@@ -37,12 +40,17 @@ import org.geysermc.floodgate.util.Utils;
public final class SpigotDataAddon implements InjectorAddon {
@Inject private FloodgateHandshakeHandler handshakeHandler;
@Inject private FloodgateConfig config;
@Inject private SimpleFloodgateApi api;
@Inject private FloodgateLogger logger;
@Inject
@Named("packetHandler")
private String packetHandlerName;
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
@Override
public void onInject(Channel channel, boolean toServer) {
channel.pipeline().addBefore(
@@ -56,6 +64,14 @@ public final class SpigotDataAddon implements InjectorAddon {
onRemoveInject(channel);
}
@Override
public void onChannelClosed(Channel channel) {
FloodgatePlayer player = channel.attr(playerAttribute).get();
if (player != null && api.removePlayer(player)) {
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getCorrectUsername());
}
}
@Override
public void onRemoveInject(Channel channel) {
Utils.removeHandler(channel.pipeline(), "floodgate_data_handler");

View File

@@ -34,7 +34,8 @@ import static org.geysermc.floodgate.util.ReflectionUtils.makeAccessible;
import static org.geysermc.floodgate.util.ReflectionUtils.setValue;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -54,7 +55,7 @@ import org.geysermc.floodgate.util.ReflectionUtils;
import org.geysermc.floodgate.util.SpigotUtils;
@RequiredArgsConstructor
public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object> {
public final class SpigotDataHandler extends ChannelInboundHandlerAdapter {
private static final Field SOCKET_ADDRESS;
private static final Class<?> HANDSHAKE_PACKET;
private static final Field HANDSHAKE_HOST;
@@ -160,7 +161,8 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
private boolean done;
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object packet) throws Exception {
public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
ReferenceCountUtil.retain(packet);
// we're done but we're not yet removed from the connection
if (done) {
ctx.fireChannelRead(packet);
@@ -244,7 +246,9 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
} finally {
// don't let the packet through if the packet is the login packet
// because we want to skip the login cycle
if (!isLogin) {
if (isLogin) {
ReferenceCountUtil.release(packet, 2);
} else {
ctx.fireChannelRead(packet);
}

View File

@@ -35,9 +35,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
@@ -45,8 +43,6 @@ import org.geysermc.floodgate.util.ReflectionUtils;
@RequiredArgsConstructor
public final class SpigotInjector extends CommonPlatformInjector {
private final Set<Channel> injectedClients = new HashSet<>();
private Object serverConnection;
private String injectedFieldName;
@@ -115,7 +111,11 @@ public final class SpigotInjector extends CommonPlatformInjector {
@Override
protected void initChannel(Channel channel) {
injectAddonsCall(channel, false);
injectedClients.add(channel);
addInjectedClient(channel);
channel.closeFuture().addListener(listener -> {
channelClosedCall(channel);
removeInjectedClient(channel);
});
}
});
}
@@ -129,10 +129,10 @@ public final class SpigotInjector extends CommonPlatformInjector {
}
// remove injection from clients
for (Channel channel : injectedClients) {
for (Channel channel : getInjectedClients()) {
removeAddonsCall(channel);
}
injectedClients.clear();
getInjectedClients().clear();
// and change the list back to the original
Object serverConnection = getServerConnection();

View File

@@ -27,11 +27,9 @@ package org.geysermc.floodgate.listener;
import com.google.inject.Inject;
import java.util.UUID;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
@@ -48,18 +46,10 @@ public final class SpigotListener implements Listener {
@Inject private LanguageManager languageManager;
@Inject private FloodgateLogger logger;
@EventHandler(priority = EventPriority.MONITOR)
public void onAsyncPreLogin(AsyncPlayerPreLoginEvent event) {
if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
api.removePlayer(event.getUniqueId(), true);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerLogin(PlayerLoginEvent event) {
UUID uniqueId = event.getPlayer().getUniqueId();
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
api.removePlayer(uniqueId);
return;
}
@@ -79,12 +69,6 @@ public final class SpigotListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
SpigotCommandUtil.AUDIENCE_CACHE.remove(player.getUniqueId()); //todo
if (api.removePlayer(player.getUniqueId()) != null) {
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getName());
}
SpigotCommandUtil.AUDIENCE_CACHE.remove(event.getPlayer().getUniqueId()); //todo
}
}

View File

@@ -75,10 +75,6 @@ public class SpigotUserAudience implements UserAudience, ForwardingAudience.Sing
@Override
public void sendMessage(@NonNull Identity source, @NonNull Component message,
@NonNull MessageType type) {
if (type != MessageType.CHAT) {
throw new IllegalStateException("Cannot send any other messages then chat messages");
}
this.source.sendMessage(GsonComponentSerializer.gson().serialize(message));
}

View File

@@ -32,6 +32,7 @@ import io.netty.util.AttributeKey;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.util.Utils;
@@ -54,6 +55,10 @@ public final class VelocityDataAddon implements InjectorAddon {
@Named("kickMessageAttribute")
private AttributeKey<String> kickMessageAttribute;
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
@Override
public void onInject(Channel channel, boolean toServer) {
if (toServer) {
@@ -75,6 +80,15 @@ public final class VelocityDataAddon implements InjectorAddon {
onRemoveInject(channel);
}
@Override
public void onChannelClosed(Channel channel) {
FloodgatePlayer player = channel.attr(playerAttribute).get();
if (player != null && api.removePlayer(player)) {
api.removeEncryptedData(player.getCorrectUniqueId());
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getUsername());
}
}
@Override
public void onRemoveInject(Channel channel) {
Utils.removeHandler(channel.pipeline(), "floodgate_data_handler");

View File

@@ -32,7 +32,7 @@ import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass;
import static org.geysermc.floodgate.util.ReflectionUtils.setValue;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil;
import java.lang.reflect.Field;
@@ -46,7 +46,7 @@ import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
@RequiredArgsConstructor
public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<Object> {
public final class VelocityProxyDataHandler extends ChannelInboundHandlerAdapter {
private static final Field HANDSHAKE;
private static final Class<?> HANDSHAKE_PACKET;
private static final Field HANDSHAKE_SERVER_ADDRESS;
@@ -76,12 +76,12 @@ public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<
private boolean done;
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ReferenceCountUtil.retain(msg);
// we're only interested in the Handshake packet
// we're only interested in the Handshake packet.
// it should be the first packet but you never know
if (done || !HANDSHAKE_PACKET.isInstance(msg)) {
ctx.fireChannelRead(msg);
done = true;
return;
}
@@ -105,7 +105,8 @@ public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<
case SUCCESS:
break;
case EXCEPTION:
ctx.channel().attr(kickMessageAttribute).set(config.getDisconnect().getInvalidKey());
ctx.channel().attr(kickMessageAttribute)
.set(config.getDisconnect().getInvalidKey());
return;
case INVALID_DATA_LENGTH:
ctx.channel().attr(kickMessageAttribute)

View File

@@ -47,6 +47,7 @@ import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
@SuppressWarnings("ConstantConditions")
@RequiredArgsConstructor
public final class VelocityServerDataHandler extends MessageToMessageEncoder<Object> {
private static final Class<?> HANDSHAKE_PACKET;
@@ -74,6 +75,7 @@ public final class VelocityServerDataHandler extends MessageToMessageEncoder<Obj
private final ProxyFloodgateConfig config;
private final ProxyFloodgateApi api;
//private final AttributeKey<FloodgatePlayer> playerAttribute;
private boolean done;
@Override
@@ -100,6 +102,14 @@ public final class VelocityServerDataHandler extends MessageToMessageEncoder<Obj
//noinspection ConstantConditions
FloodgatePlayer player = api.getPlayer(velocityPlayer.getUniqueId());
//todo use something similar to what's written below for a more direct approach
// get the Proxy <-> Player channel from the Proxy <-> Server channel
//MinecraftConnection minecraftConnection = ctx.pipeline().get("handler");
//((VelocityServerConnection) minecraftConnection.association).proxyPlayer.connection.channel
//FloodgatePlayer player = playerChannel.attr(playerAttribute).get();
// player is not a Floodgate player
if (player == null) {
out.add(packet);

View File

@@ -100,6 +100,10 @@ public final class VelocityInjector extends CommonPlatformInjector {
injector.injectAddonsCall(channel, proxyToServer);
injector.addInjectedClient(channel);
channel.closeFuture().addListener(listener -> {
injector.channelClosedCall(channel);
injector.removeInjectedClient(channel);
});
}
}
}

View File

@@ -42,7 +42,6 @@ import com.velocitypowered.api.event.connection.PreLoginEvent;
import com.velocitypowered.api.event.player.GameProfileRequestEvent;
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.util.GameProfile;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
@@ -62,7 +61,6 @@ import org.geysermc.floodgate.util.VelocityCommandUtil;
public final class VelocityListener {
private static final Field INITIAL_MINECRAFT_CONNECTION;
private static final Field MINECRAFT_CONNECTION;
private static final Field CHANNEL;
static {
@@ -70,8 +68,6 @@ public final class VelocityListener {
Class<?> minecraftConnection = getPrefixedClass("connection.MinecraftConnection");
INITIAL_MINECRAFT_CONNECTION = getFieldOfType(initialConnection, minecraftConnection);
Class<?> connectedPlayer = getPrefixedClass("connection.client.ConnectedPlayer");
MINECRAFT_CONNECTION = getFieldOfType(connectedPlayer, minecraftConnection);
CHANNEL = getFieldOfType(minecraftConnection, Channel.class);
}
@@ -167,21 +163,6 @@ public final class VelocityListener {
@Subscribe(order = PostOrder.LAST)
public void onDisconnect(DisconnectEvent event) {
Player player = event.getPlayer();
VelocityCommandUtil.AUDIENCE_CACHE.remove(player.getUniqueId()); //todo
try {
Object minecraftConnection = getValue(player, MINECRAFT_CONNECTION);
Channel channel = getCastedValue(minecraftConnection, CHANNEL);
FloodgatePlayer fPlayer = channel.attr(playerAttribute).get();
if (fPlayer != null && api.removePlayer(fPlayer)) {
api.removeEncryptedData(event.getPlayer().getUniqueId());
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getUsername());
}
} catch (Exception exception) {
logger.error("Failed to remove the player", exception);
}
VelocityCommandUtil.AUDIENCE_CACHE.remove(event.getPlayer().getUniqueId()); //todo
}
}

View File

@@ -38,7 +38,6 @@ import com.google.inject.name.Named;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.proxy.ProxyServer;
import io.netty.util.AttributeKey;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.VelocityPlugin;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
@@ -148,11 +147,4 @@ public final class VelocityPlatformModule extends AbstractModule {
public String implementationName() {
return "Velocity";
}
@Provides
@Singleton
@Named("kickMessageAttribute")
public AttributeKey<String> kickMessageAttribute() {
return AttributeKey.valueOf("floodgate-kick-message");
}
}