1
0
mirror of https://github.com/GeyserMC/Floodgate.git synced 2025-12-28 19:19:15 +00:00

Proof-of-concept for Geyser-Floodgate merge

This commit is contained in:
Camotoy
2022-11-06 21:34:29 -05:00
parent 1a9d07c5c9
commit bc76d85d7f
63 changed files with 481 additions and 446 deletions

View File

@@ -1,87 +0,0 @@
/*
* Copyright (c) 2019-2022 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.api.player;
import lombok.Getter;
@Getter
@Deprecated
public class PropertyKey {
/**
* Socket Address returns the InetSocketAddress of the Bedrock player
*/
public static final PropertyKey SOCKET_ADDRESS =
new PropertyKey("socket_address", false, false);
/**
* Skin Uploaded returns a SkinData object containing the value and signature of the Skin
*/
public static final PropertyKey SKIN_UPLOADED =
new PropertyKey("skin_uploaded", false, false);
private final String key;
private final boolean changeable;
private final boolean removable;
public PropertyKey(String key, boolean changeable, boolean removable) {
this.key = key;
this.changeable = changeable;
this.removable = removable;
}
public Result isAddAllowed(Object obj) {
if (obj instanceof PropertyKey) {
PropertyKey propertyKey = (PropertyKey) obj;
if (key.equals(propertyKey.key)) {
if ((propertyKey.changeable == changeable || propertyKey.changeable) &&
(propertyKey.removable == removable || propertyKey.removable)) {
return Result.ALLOWED;
}
return Result.INVALID_TAGS;
}
return Result.NOT_EQUALS;
}
if (obj instanceof String) {
if (key.equals(obj)) {
if (changeable) {
return Result.ALLOWED;
}
return Result.NOT_ALLOWED;
}
return Result.INVALID_TAGS;
}
return Result.NOT_EQUALS;
}
public enum Result {
NOT_EQUALS,
INVALID_TAGS,
NOT_ALLOWED,
ALLOWED
}
}

View File

@@ -11,7 +11,7 @@ allprojects {
}
val deployProjects = setOf(
projects.api,
projects.legacyApi,
// for future Floodgate integration + Fabric
projects.core,
projects.bungee,

View File

@@ -29,10 +29,10 @@ import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import org.geysermc.api.connection.Connection;
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;
@@ -60,7 +60,7 @@ public class BungeeDataAddon implements InjectorAddon {
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
private AttributeKey<Connection> playerAttribute;
@Override
public void onInject(Channel channel, boolean toServer) {
@@ -85,9 +85,9 @@ public class BungeeDataAddon implements InjectorAddon {
@Override
public void onChannelClosed(Channel channel) {
FloodgatePlayer player = channel.attr(playerAttribute).get();
Connection player = channel.attr(playerAttribute).get();
if (player != null && api.setPendingRemove(player)) {
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getCorrectUsername());
logger.translatedInfo("floodgate.ingame.disconnect_name", player.javaUsername());
}
}

View File

@@ -39,8 +39,8 @@ import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.netty.PacketHandler;
import net.md_5.bungee.protocol.packet.Handshake;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.player.FloodgatePlayerImpl;
import org.geysermc.floodgate.util.BedrockData;
import org.geysermc.floodgate.util.ReflectionUtils;
@@ -65,7 +65,7 @@ public class BungeeServerDataHandler extends ChannelOutboundHandlerAdapter {
}
private final ProxyFloodgateApi api;
private final AttributeKey<FloodgatePlayer> playerAttribute;
private final AttributeKey<Connection> playerAttribute;
@Override
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) {
@@ -83,10 +83,10 @@ public class BungeeServerDataHandler extends ChannelOutboundHandlerAdapter {
UserConnection connection = ReflectionUtils.getCastedValue(handler, USER_CONNECTION);
ChannelWrapper wrapper = ReflectionUtils.getCastedValue(connection, CHANNEL_WRAPPER);
FloodgatePlayer player = wrapper.getHandle().attr(playerAttribute).get();
Connection player = wrapper.getHandle().attr(playerAttribute).get();
if (player != null) {
BedrockData data = player.as(FloodgatePlayerImpl.class).toBedrockData();
BedrockData data = ((FloodgatePlayerImpl) player).toBedrockData();
String encryptedData = api.createEncryptedDataString(data);
Handshake handshake = (Handshake) packet;
@@ -105,7 +105,7 @@ public class BungeeServerDataHandler extends ChannelOutboundHandlerAdapter {
}
handshake.setHost(originalAddress + '\0' + encryptedData + remaining);
// Bungeecord will add his data after our data
// Bungeecord will add its data after our data
}
ctx.pipeline().remove(this);

View File

@@ -43,9 +43,9 @@ 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.api.connection.Connection;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.skin.SkinApplier;
import org.geysermc.floodgate.skin.SkinData;
@@ -74,7 +74,7 @@ public final class BungeeListener implements Listener {
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
private AttributeKey<Connection> playerAttribute;
@Inject
@Named("kickMessageAttribute")
@@ -100,11 +100,11 @@ public final class BungeeListener implements Listener {
return;
}
FloodgatePlayer player = channel.attr(playerAttribute).get();
Connection player = channel.attr(playerAttribute).get();
if (player != null) {
connection.setOnlineMode(false);
connection.setUniqueId(player.getCorrectUniqueId());
ReflectionUtils.setValue(connection, PLAYER_NAME, player.getCorrectUsername());
connection.setUniqueId(player.javaUuid());
ReflectionUtils.setValue(connection, PLAYER_NAME, player.javaUsername());
}
}
@@ -113,15 +113,15 @@ public final class BungeeListener implements Listener {
// if there was another player with the same uuid / name online,
// he has been disconnected by now
UUID uniqueId = event.getConnection().getUniqueId();
FloodgatePlayer player = api.getPlayer(uniqueId);
Connection player = api.connectionByUuid(uniqueId);
if (player != null) {
//todo we should probably move this log message earlier in the process, so that we know
// that Floodgate has done its job
logger.translatedInfo(
"floodgate.ingame.login_name",
player.getCorrectUsername(), uniqueId
player.javaUsername(), uniqueId
);
languageManager.loadLocale(player.getLanguageCode());
languageManager.loadLocale(player.languageCode());
}
}
@@ -129,7 +129,7 @@ public final class BungeeListener implements Listener {
public void onPostLogin(PostLoginEvent event) {
// To fix the February 2 2022 Mojang authentication changes
if (!config.isSendFloodgateData()) {
FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId());
Connection player = api.connectionByUuid(event.getPlayer().getUniqueId());
if (player != null && !player.isLinked() && !skinApplier.hasSkin(player)) {
skinApplier.applySkin(player, new SkinData("", ""));
}

View File

@@ -38,6 +38,7 @@ import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
@@ -96,7 +97,7 @@ public final class BungeePlatformModule extends AbstractModule {
@Provides
@Singleton
public CommandUtil commandUtil(FloodgateApi api, LanguageManager languageManager) {
public CommandUtil commandUtil(GeyserApiBase api, LanguageManager languageManager) {
return new BungeeCommandUtil(languageManager, plugin.getProxy(), api);
}

View File

@@ -40,8 +40,8 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.connection.LoginResult;
import net.md_5.bungee.protocol.Property;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.skin.SkinApplier;
import org.geysermc.floodgate.skin.SkinData;
import org.geysermc.floodgate.util.ReflectionUtils;
@@ -80,8 +80,8 @@ public final class BungeeSkinApplier implements SkinApplier {
private final FloodgateLogger logger;
@Override
public void applySkin(FloodgatePlayer uuid, SkinData skinData) {
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid.getCorrectUniqueId());
public void applySkin(Connection uuid, SkinData skinData) {
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid.javaUuid());
if (player == null) {
return;
}
@@ -114,8 +114,8 @@ public final class BungeeSkinApplier implements SkinApplier {
}
@Override
public boolean hasSkin(FloodgatePlayer fPlayer) {
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(fPlayer.getCorrectUniqueId());
public boolean hasSkin(Connection fPlayer) {
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(fPlayer.javaUuid());
if (player == null) {
return false;
}

View File

@@ -31,6 +31,7 @@ import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.player.UserAudience;
@@ -41,7 +42,7 @@ public final class BungeeCommandUtil extends CommandUtil {
private final ProxyServer server;
private UserAudience console;
public BungeeCommandUtil(LanguageManager manager, ProxyServer server, FloodgateApi api) {
public BungeeCommandUtil(LanguageManager manager, ProxyServer server, GeyserApiBase api) {
super(manager, api);
this.server = server;
}

View File

@@ -5,7 +5,8 @@ plugins {
}
dependencies {
api(projects.api)
api("org.geysermc", "api", "3.0.0-SNAPSHOT")
api("org.geysermc", "floodgate-legacy-api", "3.0.0-SNAPSHOT")
api("org.geysermc.configutils", "configutils", Versions.configUtilsVersion)
compileOnly(projects.ap)

View File

@@ -32,9 +32,12 @@ import com.google.inject.Module;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.Getter;
import org.geysermc.api.Geyser;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.InstanceHolder;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.api.impl.FloodgateApiWrapper;
import org.geysermc.floodgate.api.inject.PlatformInjector;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
@@ -64,14 +67,15 @@ public abstract class FloodgatePlatform {
config = guice.getInstance(FloodgateConfig.class);
injector = guice.getInstance(PlatformInjector.class);
GeyserApiBase api = guice.getInstance(GeyserApiBase.class);
InstanceHolder.set(
guice.getInstance(FloodgateApi.class),
new FloodgateApiWrapper(api),
guice.getInstance(PlayerLink.class),
injector,
guice.getInstance(PacketHandlers.class),
guice.getInstance(HandshakeHandlers.class),
KEY
);
Geyser.set(api);
long endTime = System.currentTimeMillis();
guice.getInstance(FloodgateLogger.class)

View File

@@ -36,7 +36,7 @@ import org.geysermc.floodgate.util.LinkedPlayer;
import org.geysermc.floodgate.util.Utils;
@Getter
public class HandshakeDataImpl implements HandshakeData {
public class HandshakeDataImpl {
private final Channel channel;
private final boolean floodgatePlayer;
private final BedrockData bedrockData;

View File

@@ -32,7 +32,7 @@ import org.geysermc.floodgate.api.handshake.HandshakeData;
import org.geysermc.floodgate.api.handshake.HandshakeHandler;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
public class HandshakeHandlersImpl implements HandshakeHandlers {
public class HandshakeHandlersImpl {
private final Random random = new Random();
private final Int2ObjectMap<HandshakeHandler> handshakeHandlers = new Int2ObjectOpenHashMap<>();

View File

@@ -27,32 +27,30 @@ package org.geysermc.floodgate.api;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableSet;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.inject.Inject;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.api.connection.Connection;
import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.util.FormBuilder;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.api.unsafe.Unsafe;
import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
import org.geysermc.floodgate.pluginmessage.channel.FormChannel;
import org.geysermc.floodgate.pluginmessage.channel.TransferChannel;
import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.HttpClient;
import org.geysermc.floodgate.util.Utils;
public class SimpleFloodgateApi implements FloodgateApi {
private final Map<UUID, FloodgatePlayer> players = new HashMap<>();
private final Cache<UUID, FloodgatePlayer> pendingRemove =
public class SimpleFloodgateApi implements GeyserApiBase {
private final Map<UUID, Connection> players = new HashMap<>();
private final Cache<UUID, Connection> pendingRemove =
CacheBuilder.newBuilder()
.expireAfterWrite(20, TimeUnit.SECONDS)
.build();
@@ -63,28 +61,28 @@ public class SimpleFloodgateApi implements FloodgateApi {
@Inject private FloodgateLogger logger;
@Override
public String getPlayerPrefix() {
public String usernamePrefix() {
return config.getUsernamePrefix();
}
@Override
public Collection<FloodgatePlayer> getPlayers() {
return ImmutableSet.copyOf(players.values());
public @NonNull List<? extends Connection> onlineConnections() {
return players.values().stream().collect(Collectors.toList()); // TODO guarantee immutable
}
@Override
public int getPlayerCount() {
public int onlineConnectionsCount() {
return players.size();
}
@Override
public boolean isFloodgatePlayer(UUID uuid) {
return getPlayer(uuid) != null;
public boolean isBedrockPlayer(@NonNull UUID uuid) {
return connectionByUuid(uuid) != null;
}
@Override
public FloodgatePlayer getPlayer(UUID uuid) {
FloodgatePlayer selfPlayer = players.get(uuid);
public @Nullable Connection connectionByUuid(@NonNull UUID uuid) {
Connection selfPlayer = players.get(uuid);
if (selfPlayer != null) {
return selfPlayer;
}
@@ -96,8 +94,9 @@ public class SimpleFloodgateApi implements FloodgateApi {
}
// make it possible to find player by Java id (linked players)
for (FloodgatePlayer player : players.values()) {
if (player.getCorrectUniqueId().equals(uuid)) {
// TODO still needed?
for (Connection player : players.values()) {
if (player.javaUuid().equals(uuid)) {
return player;
}
}
@@ -106,42 +105,32 @@ public class SimpleFloodgateApi implements FloodgateApi {
}
@Override
public UUID createJavaPlayerId(long xuid) {
return Utils.getJavaUuid(xuid);
public @Nullable Connection connectionByXuid(@NonNull String s) {
return null;
}
@Override
public boolean isFloodgateId(UUID uuid) {
return uuid.getMostSignificantBits() == 0;
}
@Override
public boolean sendForm(UUID uuid, Form form) {
public boolean sendForm(@NonNull UUID uuid, @NonNull Form form) {
return pluginMessageManager.getChannel(FormChannel.class).sendForm(uuid, form);
}
@Override
public boolean sendForm(UUID uuid, FormBuilder<?, ?, ?> formBuilder) {
public boolean sendForm(@NonNull UUID uuid, FormBuilder<?, ?, ?> formBuilder) {
return sendForm(uuid, formBuilder.build());
}
@Override
public boolean sendForm(UUID uuid, org.geysermc.cumulus.Form<?> form) {
return sendForm(uuid, form.newForm());
}
@Override
public boolean sendForm(UUID uuid, org.geysermc.cumulus.util.FormBuilder<?, ?> formBuilder) {
return sendForm(uuid, formBuilder.build());
}
@Override
public boolean transferPlayer(UUID uuid, String address, int port) {
public boolean transfer(@NonNull UUID uuid, @NonNull String address, int port) {
return pluginMessageManager
.getChannel(TransferChannel.class)
.sendTransfer(uuid, address, port);
}
/*
@Override
public CompletableFuture<Long> getXuidFor(String gamertag) {
if (gamertag == null || gamertag.isEmpty() || gamertag.length() > 16) {
@@ -184,19 +173,21 @@ public class SimpleFloodgateApi implements FloodgateApi {
" Caller: " + callerClass);
return new UnsafeFloodgateApi(pluginMessageManager);
}
*/
public FloodgatePlayer addPlayer(FloodgatePlayer player) {
public Connection addPlayer(Connection player) {
// Bedrock players are always stored by their xuid
return players.put(player.getJavaUniqueId(), player);
return players.put(player.javaUuid(), player);
}
/**
* This method is invoked when the player is no longer on the server, but the related platform-
* dependant event hasn't fired yet
* @param player
*/
public boolean setPendingRemove(FloodgatePlayer player) {
pendingRemove.put(player.getJavaUniqueId(), player);
return players.remove(player.getJavaUniqueId(), player);
public boolean setPendingRemove(Connection player) {
pendingRemove.put(player.javaUuid(), player);
return players.remove(player.javaUuid(), player);
}
public void playerRemoved(UUID correctUuid) {
@@ -206,18 +197,22 @@ public class SimpleFloodgateApi implements FloodgateApi {
pendingRemove.invalidate(correctUuid);
return;
}
FloodgatePlayer linkedPlayer = getPendingRemovePlayer(correctUuid);
Connection linkedPlayer = getPendingRemovePlayer(correctUuid);
if (linkedPlayer != null) {
pendingRemove.invalidate(linkedPlayer.getJavaUniqueId());
pendingRemove.invalidate(linkedPlayer.javaUuid());
}
}
private FloodgatePlayer getPendingRemovePlayer(UUID correctUuid) {
for (FloodgatePlayer player : pendingRemove.asMap().values()) {
if (player.getCorrectUniqueId().equals(correctUuid)) {
private Connection getPendingRemovePlayer(UUID correctUuid) {
for (Connection player : pendingRemove.asMap().values()) {
if (player.javaUuid().equals(correctUuid)) {
return player;
}
}
return null;
}
public PlayerLink getPlayerLink() { // TODO
return InstanceHolder.getPlayerLink();
}
}

View File

@@ -36,6 +36,7 @@ import com.google.inject.Inject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.link.LinkRequestResult;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
@@ -52,7 +53,7 @@ import org.geysermc.floodgate.util.Constants;
@NoArgsConstructor
public final class LinkAccountCommand implements FloodgateCommand {
@Inject private FloodgateApi api;
@Inject private SimpleFloodgateApi api;
@Inject private FloodgateLogger logger;
@Override
@@ -95,7 +96,7 @@ public final class LinkAccountCommand implements FloodgateCommand {
String targetName = targetUser.username();
// when the player is a Bedrock player
if (api.isFloodgatePlayer(sender.uuid())) {
if (api.isBedrockPlayer(sender.uuid())) {
if (!context.contains("code")) {
sender.sendMessage(Message.BEDROCK_USAGE);
return;

View File

@@ -28,6 +28,7 @@ package org.geysermc.floodgate.command;
import cloud.commandframework.Command;
import cloud.commandframework.CommandManager;
import cloud.commandframework.context.CommandContext;
import org.geysermc.api.Geyser;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.platform.command.FloodgateCommand;
@@ -45,7 +46,7 @@ public class TestCommand implements FloodgateCommand {
@Override
public void execute(CommandContext<UserAudience> context) {
int players = FloodgateApi.getInstance().getPlayers().size();
int players = Geyser.api().onlineConnectionsCount();
context.getSender().sendMessage(String.valueOf(players));
}

View File

@@ -35,6 +35,7 @@ import com.google.inject.Inject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.link.GlobalPlayerLinking;
@@ -47,7 +48,7 @@ import org.geysermc.floodgate.command.util.Permission;
@NoArgsConstructor
public final class UnlinkAccountCommand implements FloodgateCommand {
@Inject private FloodgateApi api;
@Inject private SimpleFloodgateApi api;
@Override
public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) {

View File

@@ -86,7 +86,7 @@ public class WhitelistCommand implements FloodgateCommand {
}
if (uuid != null) {
if (!FloodgateApi.getInstance().isFloodgateId(uuid)) {
if (uuid.getMostSignificantBits() != 0) { // TODO
sender.sendMessage(Message.INVALID_USERNAME);
return;
}

View File

@@ -64,9 +64,12 @@ public class FloodgateConfig implements GenericPostInitializeCallback<ConfigLoad
public CallbackResult postInitialize(ConfigLoader loader) {
Path keyPath = loader.getDataDirectory().resolve(getKeyFileName());
// don't assume that the key always exists with the existence of a config
if (!Files.exists(keyPath)) {
loader.generateKey(keyPath);
// TODO improve message and also link to article about corrupted keys/WinSCP/FTP
// Like, where is key.pem?
// TODO don't be so noisy with error. It makes it hard to understand what the error is.
return CallbackResult.failed("Floodgate requires a key file! " +
"Copy your key file from Geyser (key.pem) and paste it into " + keyPath);
}
try {

View File

@@ -39,16 +39,16 @@ import java.nio.file.Path;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import lombok.RequiredArgsConstructor;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.api.connection.Connection;
import org.geysermc.event.PostOrder;
import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.api.inject.PlatformInjector;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.packet.PacketHandlers;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ConfigLoader;
import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.crypto.AesCipher;
@@ -91,7 +91,7 @@ public class CommonModule extends AbstractModule {
bind(HttpClient.class).in(Singleton.class);
bind(FloodgateApi.class).to(SimpleFloodgateApi.class);
bind(GeyserApiBase.class).to(SimpleFloodgateApi.class);
bind(PlatformInjector.class).to(CommonPlatformInjector.class);
bind(HandshakeHandlers.class).to(HandshakeHandlersImpl.class);
@@ -151,7 +151,7 @@ public class CommonModule extends AbstractModule {
FloodgateCipher cipher,
FloodgateConfig config,
SkinUploadManager skinUploadManager,
@Named("playerAttribute") AttributeKey<FloodgatePlayer> playerAttribute,
@Named("playerAttribute") AttributeKey<Connection> playerAttribute,
FloodgateLogger logger) {
return new FloodgateHandshakeHandler(handshakeHandlers, api, cipher, config,
@@ -167,7 +167,7 @@ public class CommonModule extends AbstractModule {
@Provides
@Singleton
public SkinUploadManager skinUploadManager(
FloodgateApi api,
GeyserApiBase api,
SkinApplier skinApplier,
FloodgateLogger logger) {
return new SkinUploadManager(api, skinApplier, logger);
@@ -197,7 +197,7 @@ public class CommonModule extends AbstractModule {
@Provides
@Singleton
@Named("playerAttribute")
public AttributeKey<FloodgatePlayer> playerAttribute() {
public AttributeKey<Connection> playerAttribute() {
return AttributeKey.valueOf("floodgate-player");
}
}

View File

@@ -37,6 +37,7 @@ import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.platform.util.PlayerType;
import org.geysermc.floodgate.player.UserAudience;
@@ -51,7 +52,7 @@ import org.geysermc.floodgate.util.Utils;
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class CommandUtil {
protected final LanguageManager manager;
protected final FloodgateApi api;
protected final GeyserApiBase api;
public abstract @NonNull UserAudience getUserAudience(@NonNull Object source);
@@ -94,14 +95,14 @@ public abstract class CommandUtil {
break;
case ONLY_JAVA:
for (Object player : players) {
if (!api.isFloodgatePlayer(getUuidFromSource(player))) {
if (!api.isBedrockPlayer(getUuidFromSource(player))) {
usernames.add(getUsernameFromSource(player));
}
}
break;
case ONLY_BEDROCK:
for (Object player : players) {
if (api.isFloodgatePlayer(getUuidFromSource(player))) {
if (api.isBedrockPlayer(getUuidFromSource(player))) {
usernames.add(getUsernameFromSource(player));
}
}
@@ -133,7 +134,7 @@ public abstract class CommandUtil {
if (filter == ALL_PLAYERS || player instanceof String || player instanceof UUID) {
return player;
}
return (filter == ONLY_BEDROCK) == api.isFloodgatePlayer(getUuidFromSource(player))
return (filter == ONLY_BEDROCK) == api.isBedrockPlayer(getUuidFromSource(player))
? player
: fallback;
}

View File

@@ -41,13 +41,12 @@ import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.addon.data.HandshakeDataImpl;
import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
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.FloodgateConfig;
import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.skin.SkinUploadManager;
@@ -62,7 +61,7 @@ public final class FloodgateHandshakeHandler {
private final FloodgateCipher cipher;
private final FloodgateConfig config;
private final SkinUploadManager skinUploadManager;
private final AttributeKey<FloodgatePlayer> playerAttribute;
private final AttributeKey<Connection> playerAttribute;
private final FloodgateLogger logger;
public FloodgateHandshakeHandler(
@@ -71,7 +70,7 @@ public final class FloodgateHandshakeHandler {
FloodgateCipher cipher,
FloodgateConfig config,
SkinUploadManager skinUploadManager,
AttributeKey<FloodgatePlayer> playerAttribute,
AttributeKey<Connection> playerAttribute,
FloodgateLogger logger) {
this.handshakeHandlers = handshakeHandlers;
@@ -206,7 +205,7 @@ public final class FloodgateHandshakeHandler {
LinkedPlayer linkedPlayer) {
try {
HandshakeData handshakeData = new HandshakeDataImpl(
HandshakeDataImpl handshakeData = new HandshakeDataImpl(
channel, true, bedrockData.clone(), config,
linkedPlayer != null ? linkedPlayer.clone() : null, hostname);
@@ -221,16 +220,14 @@ public final class FloodgateHandshakeHandler {
bedrockData.getVerifyCode());
}
FloodgatePlayer player = FloodgatePlayerImpl.from(bedrockData, handshakeData);
int port = ((InetSocketAddress) channel.remoteAddress()).getPort();
Connection player = FloodgatePlayerImpl.from(bedrockData, handshakeData, port);
api.addPlayer(player);
channel.attr(playerAttribute).set(player);
int port = ((InetSocketAddress) channel.remoteAddress()).getPort();
InetSocketAddress socketAddress = new InetSocketAddress(handshakeData.getIp(), port);
player.addProperty(PropertyKey.SOCKET_ADDRESS, socketAddress);
return new HandshakeResult(ResultType.SUCCESS, handshakeData, bedrockData, player);
} catch (Exception exception) {
exception.printStackTrace();
@@ -244,7 +241,7 @@ public final class FloodgateHandshakeHandler {
BedrockData bedrockData,
String hostname) {
HandshakeData handshakeData = new HandshakeDataImpl(channel, bedrockData != null,
HandshakeInjectedData handshakeData = new HandshakeDataImpl(channel, bedrockData != null,
bedrockData, config, null, hostname);
handshakeHandlers.callHandshakeHandlers(handshakeData);
@@ -279,13 +276,13 @@ public final class FloodgateHandshakeHandler {
@Getter
public static class HandshakeResult extends IllegalStateException {
private final ResultType resultType;
private final HandshakeData handshakeData;
private final HandshakeInjectedData handshakeData;
private final BedrockData bedrockData;
private final FloodgatePlayer floodgatePlayer;
private final Connection floodgatePlayer;
public InetSocketAddress getNewIp(Channel channel) {
if (floodgatePlayer != null) {
return floodgatePlayer.getProperty(PropertyKey.SOCKET_ADDRESS);
return floodgatePlayer.socketAddress();
}
if (handshakeData.getIp() != null) {
int port = ((InetSocketAddress) channel.remoteAddress()).getPort();

View File

@@ -25,78 +25,108 @@
package org.geysermc.floodgate.player;
import java.util.HashMap;
import java.util.Map;
import java.net.InetSocketAddress;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.InstanceHolder;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.handshake.HandshakeData;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.api.player.PropertyKey;
import org.geysermc.floodgate.api.player.PropertyKey.Result;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.common.value.qual.IntRange;
import org.geysermc.api.Geyser;
import org.geysermc.api.connection.Connection;
import org.geysermc.api.util.BedrockPlatform;
import org.geysermc.api.util.InputMode;
import org.geysermc.api.util.UiProfile;
import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.util.FormBuilder;
import org.geysermc.floodgate.addon.data.HandshakeDataImpl;
import org.geysermc.floodgate.util.BedrockData;
import org.geysermc.floodgate.util.DeviceOs;
import org.geysermc.floodgate.util.InputMode;
import org.geysermc.floodgate.util.LinkedPlayer;
import org.geysermc.floodgate.util.UiProfile;
import org.geysermc.floodgate.util.Utils;
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings("unchecked")
public final class FloodgatePlayerImpl implements FloodgatePlayer {
@Builder
public final class FloodgatePlayerImpl implements Connection {
private final String version;
private final String username;
private final String javaUsername;
private final UUID javaUniqueId;
private final String xuid;
private final DeviceOs deviceOs;
private final BedrockPlatform deviceOs;
private final String languageCode;
private final UiProfile uiProfile;
private final InputMode inputMode;
private final String ip;
private final boolean fromProxy;
private final boolean proxy; // if current platform is a proxy
private final LinkedPlayer linkedPlayer;
private final int subscribeId;
private final String verifyCode;
@Getter(AccessLevel.PRIVATE)
private Map<PropertyKey, Object> propertyKeyToValue;
@Getter(AccessLevel.PRIVATE)
private Map<String, PropertyKey> stringToPropertyKey;
static FloodgatePlayerImpl from(BedrockData data, HandshakeData handshakeData) {
FloodgateApi api = InstanceHolder.getApi();
private final InetSocketAddress socketAddress;
static FloodgatePlayerImpl from(BedrockData data, HandshakeDataImpl handshakeData, int port) {
UUID javaUniqueId = Utils.getJavaUuid(data.getXuid());
DeviceOs deviceOs = DeviceOs.fromId(data.getDeviceOs());
BedrockPlatform deviceOs = BedrockPlatform.fromId(data.getDeviceOs());
UiProfile uiProfile = UiProfile.fromId(data.getUiProfile());
InputMode inputMode = InputMode.fromId(data.getInputMode());
LinkedPlayer linkedPlayer = handshakeData.getLinkedPlayer();
InetSocketAddress socketAddress = new InetSocketAddress(data.getIp(), port);
return new FloodgatePlayerImpl(
data.getVersion(), data.getUsername(), handshakeData.getJavaUsername(),
javaUniqueId, data.getXuid(), deviceOs, data.getLanguageCode(), uiProfile,
inputMode, data.getIp(), data.isFromProxy(), api instanceof ProxyFloodgateApi,
linkedPlayer, data.getSubscribeId(), data.getVerifyCode());
inputMode, data.getIp(), data.isFromProxy(),
linkedPlayer, data.getSubscribeId(), data.getVerifyCode(), socketAddress);
}
@Override
public UUID getCorrectUniqueId() {
public @NonNull String bedrockUsername() {
return username;
}
@Override
public @MonotonicNonNull String javaUsername() {
return linkedPlayer != null ? linkedPlayer.getJavaUsername() : javaUsername;
}
@Override
public @MonotonicNonNull UUID javaUuid() {
return linkedPlayer != null ? linkedPlayer.getJavaUniqueId() : javaUniqueId;
}
@Override
public String getCorrectUsername() {
return linkedPlayer != null ? linkedPlayer.getJavaUsername() : javaUsername;
public @NonNull String xuid() {
return xuid;
}
@Override
public @NonNull String version() {
return version;
}
@Override
public @NonNull BedrockPlatform platform() {
return deviceOs;
}
@Override
public @NonNull String languageCode() {
return languageCode;
}
@Override
public @NonNull UiProfile uiProfile() {
return uiProfile;
}
@Override
public @NonNull InputMode inputMode() {
return inputMode;
}
@Override
@@ -104,124 +134,29 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer {
return linkedPlayer != null;
}
@Override
public boolean sendForm(@NonNull Form form) {
return Geyser.api().sendForm(javaUuid(), form);
}
@Override
public boolean sendForm(@NonNull FormBuilder<?, ?, ?> formBuilder) {
return Geyser.api().sendForm(javaUuid(), formBuilder);
}
@Override
public boolean transfer(@NonNull String address, @IntRange(from = 0L, to = 65535L) int port) {
return Geyser.api().transfer(javaUuid(), address, port);
}
@Override
public InetSocketAddress socketAddress() {
return socketAddress;
}
public BedrockData toBedrockData() {
return BedrockData.of(version, username, xuid, deviceOs.ordinal(), languageCode,
uiProfile.ordinal(), inputMode.ordinal(), ip, linkedPlayer, proxy, subscribeId,
verifyCode);
}
@Override
public boolean hasProperty(PropertyKey key) {
if (propertyKeyToValue == null) {
return false;
}
return propertyKeyToValue.get(key) != null;
}
@Override
public boolean hasProperty(String key) {
if (stringToPropertyKey == null) {
return false;
}
return hasProperty(stringToPropertyKey.get(key));
}
@Override
public <T> T getProperty(PropertyKey key) {
if (propertyKeyToValue == null) {
return null;
}
return (T) propertyKeyToValue.get(key);
}
@Override
public <T> T getProperty(String key) {
if (stringToPropertyKey == null) {
return null;
}
return getProperty(stringToPropertyKey.get(key));
}
@Override
public <T> T removeProperty(String key) {
if (stringToPropertyKey == null) {
return null;
}
PropertyKey propertyKey = stringToPropertyKey.get(key);
if (propertyKey == null || !propertyKey.isRemovable()) {
return null;
}
return (T) propertyKeyToValue.remove(propertyKey);
}
@Override
public <T> T removeProperty(PropertyKey key) {
if (stringToPropertyKey == null) {
return null;
}
PropertyKey propertyKey = stringToPropertyKey.get(key.getKey());
if (propertyKey == null || !propertyKey.equals(key) || !propertyKey.isRemovable()) {
return null;
}
stringToPropertyKey.remove(key.getKey());
return (T) propertyKeyToValue.remove(key);
}
@Override
public <T> T addProperty(PropertyKey key, Object value) {
if (stringToPropertyKey == null) {
stringToPropertyKey = new HashMap<>();
propertyKeyToValue = new HashMap<>();
stringToPropertyKey.put(key.getKey(), key);
propertyKeyToValue.put(key, value);
return null;
}
PropertyKey propertyKey = stringToPropertyKey.get(key.getKey());
if (propertyKey != null && propertyKey.isAddAllowed(key) == Result.ALLOWED) {
stringToPropertyKey.put(key.getKey(), key);
return (T) propertyKeyToValue.put(key, value);
}
return (T) stringToPropertyKey.computeIfAbsent(key.getKey(), (keyString) -> {
propertyKeyToValue.put(key, value);
return key;
});
}
@Override
public <T> T addProperty(String key, Object value) {
PropertyKey propertyKey = new PropertyKey(key, true, true);
if (stringToPropertyKey == null) {
stringToPropertyKey = new HashMap<>();
propertyKeyToValue = new HashMap<>();
stringToPropertyKey.put(key, propertyKey);
propertyKeyToValue.put(propertyKey, value);
return null;
}
PropertyKey currentPropertyKey = stringToPropertyKey.get(key);
// key is always changeable if it passes this if statement
if (currentPropertyKey != null && currentPropertyKey.isAddAllowed(key) == Result.ALLOWED) {
stringToPropertyKey.put(key, propertyKey);
return (T) propertyKeyToValue.put(propertyKey, value);
}
return (T) stringToPropertyKey.computeIfAbsent(key, (keyString) -> {
propertyKeyToValue.put(propertyKey, value);
return propertyKey;
});
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2019-2022 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.player;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.io.ByteArrayOutputStream;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import org.geysermc.api.connection.Connection;
public final class HandshakeInjectedData {
// TIM I PROMISE THIS IS JUST AN IDEA
// public static Connection read() {
// FloodgatePlayerImpl.FloodgatePlayerImplBuilder builder = FloodgatePlayerImpl.builder();
//
// }
//
// public static String write(Connection connection) {
// ByteBuf buf = Unpooled.buffer();
// writeString(connection.version(), buf);
// writeString(connection.bedrockUsername(), buf);
// writeString(connection.xuid(), buf);
// writeVarInt(connection.platform().ordinal(), buf);
// writeString(connection.languageCode(), buf);
// writeVarInt(connection.uiProfile().ordinal(), buf);
// writeVarInt(connection.inputMode().ordinal(), buf);
// InetSocketAddress address = (InetSocketAddress) connection.socketAddress();
// writeString(address.getHostString(), buf); // TODO
// buf.writeShort(address.getPort());
// buf.writeBoolean(connection.isLinked());
// if (connection.isLinked()) {
// writeString(connection.javaUsername(), buf);
// UUID uuid = connection.javaUuid();
// buf.writeLong(uuid.getMostSignificantBits());
// buf.writeLong(uuid.getLeastSignificantBits());
// }
// }
//
// private static int readVarInt(ByteBuf buf) {
//
// }
//
// private static void writeVarInt(int i, ByteBuf buf) {
//
// }
//
// private static String readString(ByteBuf buf) {
// byte[] bytes = new byte[readVarInt(buf)];
// buf.readBytes(bytes);
// return new String(bytes, StandardCharsets.UTF_8);
// }
//
// private static void writeString(String s, ByteBuf buf) {
// byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
// writeVarInt(bytes.length, buf);
// buf.writeBytes(bytes);
// }
}

View File

@@ -29,9 +29,8 @@ import com.google.gson.JsonObject;
import com.google.inject.Inject;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.api.player.PropertyKey;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.pluginmessage.PluginMessageChannel;
@@ -39,7 +38,7 @@ import org.geysermc.floodgate.skin.SkinApplier;
import org.geysermc.floodgate.skin.SkinData;
public class SkinChannel implements PluginMessageChannel {
@Inject private FloodgateApi api;
@Inject private GeyserApiBase api;
@Inject private FloodgateConfig config;
@Inject private SkinApplier skinApplier;
@@ -76,8 +75,8 @@ public class SkinChannel implements PluginMessageChannel {
@Override
public Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername) {
FloodgatePlayer floodgatePlayer = api.getPlayer(playerUuid);
if (floodgatePlayer == null) {
Connection connection = api.connectionByUuid(playerUuid);
if (connection == null) {
return Result.kick("Player sent skins data for a non-Floodgate player");
}
@@ -89,7 +88,7 @@ public class SkinChannel implements PluginMessageChannel {
return Result.kick("Got invalid skin data");
}
if (floodgatePlayer.isLinked() || skinApplier.hasSkin(floodgatePlayer)) {
if (connection.isLinked() || skinApplier.hasSkin(connection)) {
return Result.handled();
}
@@ -102,8 +101,7 @@ public class SkinChannel implements PluginMessageChannel {
SkinData skinData = new SkinData(value, signature);
floodgatePlayer.addProperty(PropertyKey.SKIN_UPLOADED, skinData);
skinApplier.applySkin(floodgatePlayer, skinData);
skinApplier.applySkin(connection, skinData);
return Result.handled();
}

View File

@@ -25,23 +25,23 @@
package org.geysermc.floodgate.skin;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
public interface SkinApplier {
/**
* Apply a skin to a {@link FloodgatePlayer player}
*
* @param floodgatePlayer player to apply skin to
* @param connection player to apply skin to
* @param skinData data for skin to apply to player
*/
void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData);
void applySkin(Connection connection, SkinData skinData);
/**
* Check if a {@link FloodgatePlayer player} currently
* has a skin applied.
*
* @param floodgatePlayer player to check skin of
* @param connection player to check skin of
* @return if player has a skin
*/
boolean hasSkin(FloodgatePlayer floodgatePlayer);
boolean hasSkin(Connection connection);
}

View File

@@ -29,6 +29,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.AllArgsConstructor;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
@@ -37,7 +38,7 @@ public final class SkinUploadManager {
private final Int2ObjectMap<SkinUploadSocket> connections =
Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
private final FloodgateApi api;
private final GeyserApiBase api;
private final SkinApplier applier;
private final FloodgateLogger logger;

View File

@@ -34,10 +34,9 @@ import java.net.ConnectException;
import java.net.URI;
import javax.net.ssl.SSLException;
import lombok.Getter;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.api.connection.Connection;
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.util.Utils;
import org.geysermc.floodgate.util.WebsocketEventType;
import org.java_websocket.client.WebSocketClient;
@@ -47,7 +46,7 @@ final class SkinUploadSocket extends WebSocketClient {
private static final Gson gson = new Gson();
private final SkinUploadManager uploadManager;
private final FloodgateApi api;
private final GeyserApiBase api;
private final SkinApplier applier;
private final FloodgateLogger logger;
@@ -59,7 +58,7 @@ final class SkinUploadSocket extends WebSocketClient {
int id,
String verifyCode,
SkinUploadManager uploadManager,
FloodgateApi api,
GeyserApiBase api,
SkinApplier applier,
FloodgateLogger logger) {
@@ -107,16 +106,15 @@ final class SkinUploadSocket extends WebSocketClient {
break;
case SKIN_UPLOADED:
String xuid = message.get("xuid").getAsString();
FloodgatePlayer player = api.getPlayer(Utils.getJavaUuid(xuid));
Connection player = api.connectionByUuid(Utils.getJavaUuid(xuid));
if (player != null) {
if (!message.get("success").getAsBoolean()) {
logger.info("Failed to upload skin for {} ({})", xuid,
player.getCorrectUsername());
player.javaUsername());
return;
}
if (!player.isLinked() && !applier.hasSkin(player)) {
SkinData skinData = SkinData.from(message.getAsJsonObject("data"));
player.addProperty(PropertyKey.SKIN_UPLOADED, skinData);
applier.applySkin(player, skinData);
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.util;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* This class contains the raw data send by Geyser to Floodgate or from Floodgate to Floodgate. This
* class is only used internally, and you should look at FloodgatePlayer instead (FloodgatePlayer is
* present in the API module of the Floodgate repo)
*/
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class BedrockData implements Cloneable {
public static final int EXPECTED_LENGTH = 12;
private final String version;
private final String username;
private final String xuid;
private final int deviceOs;
private final String languageCode;
private final int uiProfile;
private final int inputMode;
private final String ip;
private final LinkedPlayer linkedPlayer;
private final boolean fromProxy;
private final int subscribeId;
private final String verifyCode;
private final int dataLength;
public static BedrockData of(
String version, String username, String xuid, int deviceOs,
String languageCode, int uiProfile, int inputMode, String ip,
LinkedPlayer linkedPlayer, boolean fromProxy, int subscribeId,
String verifyCode) {
return new BedrockData(version, username, xuid, deviceOs, languageCode, inputMode,
uiProfile, ip, linkedPlayer, fromProxy, subscribeId, verifyCode, EXPECTED_LENGTH);
}
public static BedrockData of(
String version, String username, String xuid, int deviceOs,
String languageCode, int uiProfile, int inputMode, String ip,
int subscribeId, String verifyCode) {
return of(version, username, xuid, deviceOs, languageCode, uiProfile, inputMode, ip, null,
false, subscribeId, verifyCode);
}
public static BedrockData fromString(String data) {
String[] split = data.split("\0");
if (split.length != EXPECTED_LENGTH) {
return emptyData(split.length);
}
LinkedPlayer linkedPlayer = LinkedPlayer.fromString(split[8]);
// The format is the same as the order of the fields in this class
return new BedrockData(
split[0], split[1], split[2], Integer.parseInt(split[3]), split[4],
Integer.parseInt(split[5]), Integer.parseInt(split[6]), split[7], linkedPlayer,
"1".equals(split[9]), Integer.parseInt(split[10]), split[11], split.length
);
}
private static BedrockData emptyData(int dataLength) {
return new BedrockData(null, null, null, -1, null, -1, -1, null, null, false, -1, null,
dataLength);
}
public boolean hasPlayerLink() {
return linkedPlayer != null;
}
@Override
public String toString() {
// The format is the same as the order of the fields in this class
return version + '\0' + username + '\0' + xuid + '\0' + deviceOs + '\0' +
languageCode + '\0' + uiProfile + '\0' + inputMode + '\0' + ip + '\0' +
(linkedPlayer != null ? linkedPlayer.toString() : "null") + '\0' +
(fromProxy ? 1 : 0) + '\0' + subscribeId + '\0' + verifyCode;
}
@Override
public BedrockData clone() throws CloneNotSupportedException {
return (BedrockData) super.clone();
}
}

View File

@@ -38,6 +38,7 @@ import org.bstats.charts.DrilldownPie;
import org.bstats.charts.SimplePie;
import org.bstats.charts.SingleLineChart;
import org.bstats.json.JsonObjectBuilder;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig;
@@ -49,7 +50,7 @@ public final class Metrics {
private final MetricsBase metricsBase;
@Inject
Metrics(FloodgateConfig config, PlatformUtils platformUtils, FloodgateApi api,
Metrics(FloodgateConfig config, PlatformUtils platformUtils, GeyserApiBase api,
@Named("implementationName") String implementationName, FloodgateLogger logger) {
MetricsConfig metricsConfig = config.getMetrics();
@@ -71,12 +72,12 @@ public final class Metrics {
);
metricsBase.addCustomChart(
new SingleLineChart("players", api::getPlayerCount)
new SingleLineChart("players", api::onlineConnectionsCount)
);
metricsBase.addCustomChart(
new DrilldownPie("player_count", () -> {
int playerCount = api.getPlayerCount();
int playerCount = api.onlineConnectionsCount();
// 0 = 0 - 4, 9 = 5 - 9, etc.
int category = playerCount / 5 * 5;
String categoryName = category + " - " + (category + 4);

View File

@@ -143,30 +143,6 @@ public interface FloodgatePlayer {
return FloodgateApi.getInstance().transferPlayer(getCorrectUniqueId(), address, port);
}
@Deprecated
boolean hasProperty(PropertyKey key);
@Deprecated
boolean hasProperty(String key);
@Deprecated
<T> T getProperty(PropertyKey key);
@Deprecated
<T> T getProperty(String key);
@Deprecated
<T> T removeProperty(PropertyKey key);
@Deprecated
<T> T removeProperty(String key);
@Deprecated
<T> T addProperty(PropertyKey key, Object value);
@Deprecated
<T> T addProperty(String key, Object value);
/**
* Casts the FloodgatePlayer instance to a class that extends FloodgatePlayer.
*

View File

@@ -3,7 +3,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
// mavenLocal()
mavenLocal()
// Geyser, Cumulus etc.
maven("https://repo.opencollab.dev/maven-releases") {
@@ -62,7 +62,7 @@ pluginManagement {
rootProject.name = "floodgate-parent"
include(":api")
include(":legacy-api")
include(":ap")
include(":core")
include(":bungee")

View File

@@ -39,6 +39,7 @@ public final class SpigotPlugin extends JavaPlugin {
@Override
public void onEnable() {
// TODO don't enable if onLoad failed
try {
platform.enable();
} catch (Exception exception) {

View File

@@ -29,11 +29,12 @@ import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import org.geysermc.api.connection.Connection;
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.Connection;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
public final class SpigotDataAddon implements InjectorAddon {
@@ -52,7 +53,7 @@ public final class SpigotDataAddon implements InjectorAddon {
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
private AttributeKey<Connection> playerAttribute;
@Override
public void onInject(Channel channel, boolean toServer) {
@@ -65,9 +66,9 @@ public final class SpigotDataAddon implements InjectorAddon {
@Override
public void onChannelClosed(Channel channel) {
FloodgatePlayer player = channel.attr(playerAttribute).get();
Connection player = channel.attr(playerAttribute).get();
if (player != null && api.setPendingRemove(player)) {
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getCorrectUsername());
logger.translatedInfo("floodgate.ingame.disconnect_name", player.javaUsername());
}
}

View File

@@ -34,6 +34,7 @@ import io.netty.util.AttributeKey;
import java.net.InetSocketAddress;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.player.Connection;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
import org.geysermc.floodgate.util.ClassNames;
@@ -41,7 +42,7 @@ import org.geysermc.floodgate.util.ProxyUtils;
public final class SpigotDataHandler extends CommonDataHandler {
private Object networkManager;
private FloodgatePlayer player;
private Connection player;
private boolean proxyData;
public SpigotDataHandler(
@@ -80,7 +81,7 @@ public final class SpigotDataHandler extends CommonDataHandler {
if (!proxyData) {
// Use a spoofedUUID for initUUID (just like Bungeecord)
setValue(networkManager, "spoofedUUID", player.getCorrectUniqueId());
setValue(networkManager, "spoofedUUID", player.javaUuid());
}
// we can only remove the handler if the data is proxy data and username validation doesn't
@@ -150,7 +151,7 @@ public final class SpigotDataHandler extends CommonDataHandler {
// set the player his GameProfile, we can't change the username without this
GameProfile gameProfile = new GameProfile(
player.getCorrectUniqueId(), player.getCorrectUsername()
player.javaUuid(), player.javaUsername()
);
setValue(packetListener, ClassNames.LOGIN_PROFILE, gameProfile);

View File

@@ -33,6 +33,7 @@ import java.util.Set;
import java.util.UUID;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
@@ -46,7 +47,7 @@ public final class PaperProfileListener implements Listener {
return;
}
FloodgatePlayer player = api.getPlayer(id);
Connection player = api.connectionByUuid(id);
if (player == null || player.isLinked()) {
return;
}

View File

@@ -32,9 +32,9 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.util.LanguageManager;
public final class SpigotListener implements Listener {
@@ -51,15 +51,15 @@ public final class SpigotListener implements Listener {
// if there was another player with the same uuid online,
// he would've been disconnected by now
FloodgatePlayer player = api.getPlayer(uniqueId);
Connection player = api.connectionByUuid(uniqueId);
if (player != null) {
//todo we should probably move this log message earlier in the process, so that we know
// that Floodgate has done its job
logger.translatedInfo(
"floodgate.ingame.login_name",
player.getCorrectUsername(), player.getCorrectUniqueId()
player.javaUsername(), player.javaUuid()
);
languageManager.loadLocale(player.getLanguageCode());
languageManager.loadLocale(player.languageCode());
}
}

View File

@@ -34,6 +34,7 @@ import java.util.logging.Logger;
import lombok.RequiredArgsConstructor;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
@@ -78,7 +79,7 @@ public final class SpigotPlatformModule extends AbstractModule {
@Provides
@Singleton
public CommandUtil commandUtil(
FloodgateApi api,
GeyserApiBase api,
SpigotVersionSpecificMethods versionSpecificMethods,
LanguageManager languageManager) {
return new SpigotCommandUtil(

View File

@@ -32,6 +32,7 @@ import com.mojang.authlib.properties.PropertyMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.skin.SkinApplier;
import org.geysermc.floodgate.skin.SkinData;
@@ -51,13 +52,13 @@ public final class SpigotSkinApplier implements SkinApplier {
}
@Override
public void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData) {
applySkin0(floodgatePlayer, skinData, true);
public void applySkin(Connection connection, SkinData skinData) {
applySkin0(connection, skinData, true);
}
@Override
public boolean hasSkin(FloodgatePlayer floodgatePlayer) {
Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId());
public boolean hasSkin(Connection connection) {
Player player = Bukkit.getPlayer(connection.javaUuid());
if (player == null) {
return false;
@@ -73,8 +74,8 @@ public final class SpigotSkinApplier implements SkinApplier {
return false;
}
private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, boolean firstTry) {
Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId());
private void applySkin0(Connection floodgatePlayer, SkinData skinData, boolean firstTry) {
Player player = Bukkit.getPlayer(floodgatePlayer.javaUuid());
// player is probably not logged in yet
if (player == null) {

View File

@@ -33,6 +33,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.player.UserAudience;
@@ -48,7 +49,7 @@ public final class SpigotCommandUtil extends CommandUtil {
public SpigotCommandUtil(
LanguageManager manager,
Server server,
FloodgateApi api,
GeyserApiBase api,
SpigotVersionSpecificMethods versionSpecificMethods,
JavaPlugin plugin) {
super(manager, api);

View File

@@ -35,6 +35,7 @@ import java.util.UUID;
import org.geysermc.floodgate.api.packet.PacketHandler;
import org.geysermc.floodgate.api.packet.PacketHandlers;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.player.Connection;
public class SpigotProtocolSupportHandler implements PacketHandler {
private static final Method getFromChannel;
@@ -81,7 +82,7 @@ public class SpigotProtocolSupportHandler implements PacketHandler {
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
private AttributeKey<Connection> playerAttribute;
@Inject
public void register(PacketHandlers packetHandlers) {
@@ -90,7 +91,7 @@ public class SpigotProtocolSupportHandler implements PacketHandler {
@Override
public Object handle(ChannelHandlerContext ctx, Object packet, boolean serverbound) {
FloodgatePlayer player = ctx.channel().attr(playerAttribute).get();
Connection player = ctx.channel().attr(playerAttribute).get();
if (player == null) {
return packet;
}
@@ -99,14 +100,14 @@ public class SpigotProtocolSupportHandler implements PacketHandler {
Object profile = ReflectionUtils.invoke(connection, getLoginProfile);
// set correct uuid and name on ProtocolSupport's end, since we skip the LoginStart
ReflectionUtils.invoke(profile, setName, player.getCorrectUsername());
ReflectionUtils.invoke(profile, setOriginalName, player.getCorrectUsername());
ReflectionUtils.invoke(profile, setUuid, player.getCorrectUniqueId());
ReflectionUtils.invoke(profile, setOriginalUuid, player.getCorrectUniqueId());
ReflectionUtils.invoke(profile, setName, player.javaUsername());
ReflectionUtils.invoke(profile, setOriginalName, player.javaUsername());
ReflectionUtils.invoke(profile, setUuid, player.javaUuid());
ReflectionUtils.invoke(profile, setOriginalUuid, player.javaUuid());
Object temp = ReflectionUtils.invoke(connection, getNetworkManagerWrapper);
temp = ReflectionUtils.invoke(temp, getPacketListener);
ReflectionUtils.invoke(temp, handleLoginStart, player.getCorrectUsername());
ReflectionUtils.invoke(temp, handleLoginStart, player.javaUsername());
return packet;
}
}

View File

@@ -34,6 +34,7 @@ import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.geysermc.api.Geyser;
import org.geysermc.floodgate.api.FloodgateApi;
@SuppressWarnings("unchecked")
@@ -69,7 +70,7 @@ public final class SpigotProtocolSupportListener {
return;
}
if (FloodgateApi.getInstance().isFloodgatePlayer(uuid)) {
if (Geyser.api().isBedrockPlayer(uuid)) {
// otherwise ProtocolSupport attempts to connect with online mode
ReflectionUtils.invoke(event, setOnlineMode, false);
}

View File

@@ -35,6 +35,7 @@ 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.Connection;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
public final class VelocityDataAddon implements InjectorAddon {
@@ -62,7 +63,7 @@ public final class VelocityDataAddon implements InjectorAddon {
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
private AttributeKey<Connection> playerAttribute;
@Override
public void onInject(Channel channel, boolean toServer) {
@@ -88,9 +89,9 @@ public final class VelocityDataAddon implements InjectorAddon {
@Override
public void onChannelClosed(Channel channel) {
FloodgatePlayer player = channel.attr(playerAttribute).get();
Connection player = channel.attr(playerAttribute).get();
if (player != null && api.setPendingRemove(player)) {
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getUsername());
logger.translatedInfo("floodgate.ingame.disconnect_name", player.javaUsername());
}
}

View File

@@ -41,6 +41,7 @@ import java.net.InetSocketAddress;
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.Connection;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.ResultType;
@@ -113,9 +114,9 @@ public final class VelocityProxyDataHandler extends CommonDataHandler {
@Override
protected boolean shouldRemoveHandler(HandshakeResult result) {
if (result.getResultType() == ResultType.SUCCESS) {
FloodgatePlayer player = result.getFloodgatePlayer();
Connection player = result.getFloodgatePlayer();
logger.info("Floodgate player who is logged in as {} {} joined",
player.getCorrectUsername(), player.getCorrectUniqueId());
player.javaUsername(), player.javaUuid());
// the way Velocity stores whether to force key authentication
boolean forceKeyAuthentication = Boolean.getBoolean("auth.forceSecureProfiles");

View File

@@ -41,8 +41,8 @@ import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.player.FloodgatePlayerImpl;
import org.geysermc.floodgate.util.BedrockData;
@@ -101,7 +101,7 @@ public final class VelocityServerDataHandler extends ChannelOutboundHandlerAdapt
Player velocityPlayer = castedInvoke(association, GET_PLAYER);
//noinspection ConstantConditions
FloodgatePlayer player = api.getPlayer(velocityPlayer.getUniqueId());
Connection player = api.connectionByUuid(velocityPlayer.getUniqueId());
//todo use something similar to what's written below for a more direct approach
@@ -112,7 +112,7 @@ public final class VelocityServerDataHandler extends ChannelOutboundHandlerAdapt
//FloodgatePlayer player = playerChannel.attr(playerAttribute).get();
if (player != null) {
// Player is a Floodgate player
BedrockData data = player.as(FloodgatePlayerImpl.class).toBedrockData();
BedrockData data = ((FloodgatePlayerImpl) player).toBedrockData();
String encryptedData = api.createEncryptedDataString(data);
// use the same system that we use on bungee, our data goes before all the other data

View File

@@ -52,9 +52,9 @@ import java.util.Collections;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import net.kyori.adventure.text.Component;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.util.LanguageManager;
@@ -84,7 +84,7 @@ public final class VelocityListener {
CHANNEL = getFieldOfType(minecraftConnection, Channel.class);
}
private final Cache<InboundConnection, FloodgatePlayer> playerCache =
private final Cache<InboundConnection, Connection> playerCache =
CacheBuilder.newBuilder()
.maximumSize(500)
.expireAfterAccess(20, TimeUnit.SECONDS)
@@ -97,7 +97,7 @@ public final class VelocityListener {
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
private AttributeKey<Connection> playerAttribute;
@Inject
@Named("kickMessageAttribute")
@@ -105,7 +105,7 @@ public final class VelocityListener {
@Subscribe(order = PostOrder.EARLY)
public void onPreLogin(PreLoginEvent event) {
FloodgatePlayer player = null;
Connection player = null;
String kickMessage;
try {
InboundConnection connection = event.getConnection();
@@ -140,13 +140,13 @@ public final class VelocityListener {
@Subscribe(order = PostOrder.EARLY)
public void onGameProfileRequest(GameProfileRequestEvent event) {
FloodgatePlayer player = playerCache.getIfPresent(event.getConnection());
Connection player = playerCache.getIfPresent(event.getConnection());
if (player != null) {
playerCache.invalidate(event.getConnection());
GameProfile profile = new GameProfile(
player.getCorrectUniqueId(),
player.getCorrectUsername(),
player.javaUuid(),
player.javaUsername(),
Collections.emptyList()
);
// The texture properties addition is to fix the February 2 2022 Mojang authentication changes
@@ -160,9 +160,9 @@ public final class VelocityListener {
@Subscribe(order = PostOrder.LAST)
public void onLogin(LoginEvent event) {
if (event.getResult().isAllowed()) {
FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId());
Connection player = api.connectionByUuid(event.getPlayer().getUniqueId());
if (player != null) {
languageManager.loadLocale(player.getLanguageCode());
languageManager.loadLocale(player.languageCode());
}
}
}

View File

@@ -34,6 +34,7 @@ import java.util.Optional;
import java.util.UUID;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.player.UserAudience;
@@ -46,7 +47,7 @@ public final class VelocityCommandUtil extends CommandUtil {
@Inject private ProxyServer server;
@Inject
public VelocityCommandUtil(LanguageManager manager, FloodgateApi api) {
public VelocityCommandUtil(LanguageManager manager, GeyserApiBase api) {
super(manager, api);
}

View File

@@ -32,7 +32,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.skin.SkinApplier;
import org.geysermc.floodgate.skin.SkinData;
@@ -41,8 +41,8 @@ public class VelocitySkinApplier implements SkinApplier {
private final ProxyServer server;
@Override
public void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData) {
server.getPlayer(floodgatePlayer.getCorrectUniqueId()).ifPresent(player -> {
public void applySkin(Connection connection, SkinData skinData) {
server.getPlayer(connection.javaUuid()).ifPresent(player -> {
List<Property> properties = new ArrayList<>(player.getGameProfileProperties());
properties.add(new Property("textures", skinData.getValue(), skinData.getSignature()));
player.setGameProfileProperties(properties);
@@ -50,8 +50,8 @@ public class VelocitySkinApplier implements SkinApplier {
}
@Override
public boolean hasSkin(FloodgatePlayer floodgatePlayer) {
Optional<Player> player = server.getPlayer(floodgatePlayer.getCorrectUniqueId());
public boolean hasSkin(Connection connection) {
Optional<Player> player = server.getPlayer(connection.javaUuid());
if (player.isPresent()) {
for (Property property : player.get().getGameProfileProperties()) {