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

Allow Floodgate to run embedded. Support Velocity's 'none' forwarding

The classes that were removed from the legacy Floodgate API have also been brought back
This commit is contained in:
Tim203
2022-11-10 20:25:30 +01:00
parent ee82c80c47
commit 59c2c6daf3
35 changed files with 747 additions and 100 deletions

View File

@@ -5,8 +5,8 @@ plugins {
}
dependencies {
api("org.geysermc", "api", "3.0.0-SNAPSHOT")
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)

View File

@@ -29,13 +29,15 @@ import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import java.util.List;
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.impl.FloodgateApiWrapper;
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;
@@ -67,10 +69,11 @@ public abstract class FloodgatePlatform {
GeyserApiBase api = guice.getInstance(GeyserApiBase.class);
InstanceHolder.set(
new FloodgateApiWrapper(api),
guice.getInstance(FloodgateApi.class),
guice.getInstance(PlayerLink.class),
injector,
guice.getInstance(PacketHandlers.class),
guice.getInstance(HandshakeHandlers.class),
KEY
);
Geyser.set(api);
@@ -80,7 +83,7 @@ public abstract class FloodgatePlatform {
.translatedInfo("floodgate.core.finish", endTime - startTime);
}
protected abstract Module[] loadStageModules();
protected abstract List<Module> loadStageModules();
public void enable() throws RuntimeException {
if (injector == null) {
@@ -98,7 +101,7 @@ public abstract class FloodgatePlatform {
guice.getInstance(EventBus.class).fire(new PostEnableEvent());
}
protected abstract Module[] postEnableStageModules();
protected abstract List<Module> postEnableStageModules();
public void disable() {
guice.getInstance(EventBus.class).fire(new ShutdownEvent());
@@ -115,4 +118,8 @@ public abstract class FloodgatePlatform {
public boolean isProxy() {
return config.isProxy();
}
public <T> T getInstance(Class<T> clazz) {
return guice.getInstance(clazz);
}
}

View File

@@ -25,6 +25,7 @@
package org.geysermc.floodgate.addon.data;
import com.google.inject.Singleton;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.Random;
@@ -32,7 +33,8 @@ import org.geysermc.floodgate.api.handshake.HandshakeData;
import org.geysermc.floodgate.api.handshake.HandshakeHandler;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
public class HandshakeHandlersImpl {
@Singleton
public class HandshakeHandlersImpl implements HandshakeHandlers {
private final Random random = new Random();
private final Int2ObjectMap<HandshakeHandler> handshakeHandlers = new Int2ObjectOpenHashMap<>();

View File

@@ -26,10 +26,12 @@
package org.geysermc.floodgate.api;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.nio.charset.StandardCharsets;
import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.util.BedrockData;
@Singleton
public final class ProxyFloodgateApi extends SimpleFloodgateApi {
@Inject
private FloodgateCipher cipher;

View File

@@ -28,6 +28,7 @@ package org.geysermc.floodgate.api;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -48,6 +49,7 @@ import org.geysermc.floodgate.pluginmessage.channel.FormChannel;
import org.geysermc.floodgate.pluginmessage.channel.TransferChannel;
import org.geysermc.floodgate.util.HttpClient;
@Singleton
public class SimpleFloodgateApi implements GeyserApiBase {
private final Map<UUID, Connection> players = new HashMap<>();
private final Cache<UUID, Connection> pendingRemove =

View File

@@ -0,0 +1,131 @@
/*
* 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.legacy;
import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.util.FormBuilder;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.api.unsafe.Unsafe;
import org.geysermc.floodgate.player.FloodgateConnection;
import org.geysermc.floodgate.util.WebEndpoints;
public final class LegacyApiWrapper implements FloodgateApi {
private final GeyserApiBase apiBase;
private final WebEndpoints webEndpoints;
public LegacyApiWrapper(GeyserApiBase apiBase, WebEndpoints webEndpoints) {
this.apiBase = apiBase;
this.webEndpoints = webEndpoints;
}
@Override
public String getPlayerPrefix() {
return apiBase.usernamePrefix();
}
@Override
public Collection<FloodgatePlayer> getPlayers() {
return apiBase.onlineConnections()
.stream()
.map(connection -> new LegacyPlayerWrapper((FloodgateConnection) connection))
.collect(Collectors.toList());
}
@Override
public int getPlayerCount() {
return apiBase.onlineConnectionsCount();
}
@Override
public boolean isFloodgatePlayer(UUID uuid) {
return apiBase.isBedrockPlayer(uuid);
}
@Override
public FloodgatePlayer getPlayer(UUID uuid) {
FloodgateConnection connection = (FloodgateConnection) apiBase.connectionByUuid(uuid);
if (connection != null) {
return new LegacyPlayerWrapper(connection);
}
return null;
}
@Override
public UUID createJavaPlayerId(long xuid) {
return new UUID(0, xuid);
}
@Override
public boolean isFloodgateId(UUID uuid) {
return uuid.getMostSignificantBits() == 0;
}
@Override
public boolean sendForm(UUID uuid, Form form) {
return apiBase.sendForm(uuid, form);
}
@Override
public boolean sendForm(UUID uuid, FormBuilder<?, ?, ?> formBuilder) {
return apiBase.sendForm(uuid, formBuilder);
}
@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) {
return apiBase.transfer(uuid, address, port);
}
@Override
public CompletableFuture<Long> getXuidFor(String gamertag) {
return webEndpoints.getXuidFor(gamertag);
}
@Override
public CompletableFuture<String> getGamertagFor(long xuid) {
return webEndpoints.getGamertagFor(xuid);
}
@Override
public Unsafe unsafe() {
return null;
}
}

View File

@@ -0,0 +1,160 @@
/*
* 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.legacy;
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.floodgate.player.FloodgateConnection;
import org.geysermc.floodgate.util.DeviceOs;
import org.geysermc.floodgate.util.InputMode;
import org.geysermc.floodgate.util.LinkedPlayer;
import org.geysermc.floodgate.util.UiProfile;
public class LegacyPlayerWrapper implements FloodgatePlayer {
private final FloodgateConnection connection;
public LegacyPlayerWrapper(FloodgateConnection connection) {
this.connection = connection;
}
@Override
public String getJavaUsername() {
throw new UnsupportedOperationException(); //todo
}
@Override
public UUID getJavaUniqueId() {
throw new UnsupportedOperationException(); //todo
}
@Override
public UUID getCorrectUniqueId() {
return connection.javaUuid();
}
@Override
public String getCorrectUsername() {
return connection.javaUsername();
}
@Override
public String getVersion() {
return connection.version();
}
@Override
public String getUsername() {
return connection.bedrockUsername();
}
@Override
public String getXuid() {
return connection.xuid();
}
@Override
public DeviceOs getDeviceOs() {
return DeviceOs.fromId(connection.platform().ordinal());
}
@Override
public String getLanguageCode() {
return connection.languageCode();
}
@Override
public UiProfile getUiProfile() {
return UiProfile.fromId(connection.uiProfile().ordinal());
}
@Override
public InputMode getInputMode() {
return InputMode.fromId(connection.inputMode().ordinal());
}
@Override
public boolean isFromProxy() {
throw new UnsupportedOperationException(); //todo
}
@Override
public LinkedPlayer getLinkedPlayer() {
if (isLinked()) {
return LinkedPlayer.of(
connection.javaUsername(), connection.javaUuid(),
FloodgateApi.getInstance().createJavaPlayerId(Long.parseLong(getXuid()))
);
}
return null;
}
@Override
public boolean isLinked() {
return connection.isLinked();
}
@Override
public boolean hasProperty(PropertyKey key) {
return connection.propertyGlue().hasProperty(key);
}
@Override
public boolean hasProperty(String key) {
return connection.propertyGlue().hasProperty(key);
}
@Override
public <T> T getProperty(PropertyKey key) {
return connection.propertyGlue().getProperty(key);
}
@Override
public <T> T getProperty(String key) {
return connection.propertyGlue().getProperty(key);
}
@Override
public <T> T removeProperty(PropertyKey key) {
return connection.propertyGlue().removeProperty(key);
}
@Override
public <T> T removeProperty(String key) {
return connection.propertyGlue().removeProperty(key);
}
@Override
public <T> T addProperty(PropertyKey key, Object value) {
return connection.propertyGlue().addProperty(key, value);
}
@Override
public <T> T addProperty(String key, Object value) {
return connection.propertyGlue().addProperty(key, value);
}
}

View File

@@ -0,0 +1,148 @@
/*
* 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.legacy;
import java.util.HashMap;
import java.util.Map;
import lombok.AccessLevel;
import lombok.Getter;
import org.geysermc.floodgate.api.player.PropertyKey;
import org.geysermc.floodgate.api.player.PropertyKey.Result;
@SuppressWarnings("unchecked")
public class PropertyGlue {
@Getter(AccessLevel.PRIVATE)
private Map<PropertyKey, Object> propertyKeyToValue;
@Getter(AccessLevel.PRIVATE)
private Map<String, PropertyKey> stringToPropertyKey;
public boolean hasProperty(PropertyKey key) {
if (propertyKeyToValue == null) {
return false;
}
return propertyKeyToValue.get(key) != null;
}
public boolean hasProperty(String key) {
if (stringToPropertyKey == null) {
return false;
}
return hasProperty(stringToPropertyKey.get(key));
}
public <T> T getProperty(PropertyKey key) {
if (propertyKeyToValue == null) {
return null;
}
return (T) propertyKeyToValue.get(key);
}
public <T> T getProperty(String key) {
if (stringToPropertyKey == null) {
return null;
}
return getProperty(stringToPropertyKey.get(key));
}
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);
}
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);
}
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;
});
}
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

@@ -25,12 +25,14 @@
package org.geysermc.floodgate.config;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.Key;
import java.util.UUID;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.configutils.ConfigUtilities;
import org.geysermc.configutils.file.codec.PathFileCodec;
import org.geysermc.configutils.file.template.ResourceTemplateReader;
@@ -39,13 +41,26 @@ import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.crypto.KeyProducer;
@Getter
@RequiredArgsConstructor
@Singleton
public final class ConfigLoader {
private final Path dataDirectory;
private final Class<? extends FloodgateConfig> configClass;
@Inject
@Named("dataDirectory")
private Path dataDirectory;
private final KeyProducer keyProducer;
private final FloodgateCipher cipher;
@Inject
@Named("configClass")
private Class<? extends FloodgateConfig> configClass;
@Inject
private KeyProducer keyProducer;
@Inject
private FloodgateCipher cipher;
@Inject(optional = true)
@Named("configFile")
private String configFile = "config.yml";
@SuppressWarnings("unchecked")
public <T extends FloodgateConfig> T load() {
@@ -53,6 +68,7 @@ public final class ConfigLoader {
if (ProxyFloodgateConfig.class.isAssignableFrom(configClass)) {
templateFile = "proxy-" + templateFile;
}
templateFile = "floodgate-" + templateFile;
//todo old Floodgate logged a message when version = 0 and it generated a new key.
// Might be nice to allow you to run a function for a specific version.
@@ -63,7 +79,7 @@ public final class ConfigLoader {
ConfigUtilities utilities =
ConfigUtilities.builder()
.fileCodec(PathFileCodec.of(dataDirectory))
.configFile("config.yml")
.configFile(configFile)
.templateReader(ResourceTemplateReader.of(getClass()))
.template(templateFile)
.changes(Changes.builder()

View File

@@ -43,9 +43,11 @@ 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.legacy.LegacyApiWrapper;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.packet.PacketHandlers;
@@ -67,7 +69,7 @@ import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
import org.geysermc.floodgate.skin.SkinApplier;
import org.geysermc.floodgate.skin.SkinUploadManager;
import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.HttpClient;
import org.geysermc.floodgate.util.WebEndpoints;
@RequiredArgsConstructor
public class CommonModule extends AbstractModule {
@@ -89,13 +91,10 @@ public class CommonModule extends AbstractModule {
eventBus.subscribe(ShutdownEvent.class, ignored -> commonPool.shutdown(), PostOrder.LAST);
bind(ExecutorService.class).annotatedWith(Names.named("commonPool")).toInstance(commonPool);
bind(HttpClient.class).in(Singleton.class);
bind(GeyserApiBase.class).to(SimpleFloodgateApi.class);
bind(PlatformInjector.class).to(CommonPlatformInjector.class);
bind(HandshakeHandlers.class).to(HandshakeHandlersImpl.class);
bind(HandshakeHandlersImpl.class).in(Singleton.class);
bind(PacketHandlers.class).to(PacketHandlersImpl.class);
bind(PacketHandlersImpl.class).asEagerSingleton();
@@ -103,6 +102,12 @@ public class CommonModule extends AbstractModule {
install(new AutoBindModule());
}
@Provides
@Singleton
public FloodgateApi floodgateApi(GeyserApiBase api, WebEndpoints webEndpoints) {
return new LegacyApiWrapper(api, webEndpoints);
}
@Provides
@Singleton
public FloodgateConfig floodgateConfig(ConfigLoader configLoader) {
@@ -134,15 +139,6 @@ public class CommonModule extends AbstractModule {
return dataDirectory;
}
@Provides
@Singleton
public ConfigLoader configLoader(
@Named("configClass") Class<? extends FloodgateConfig> configClass,
KeyProducer producer,
FloodgateCipher cipher) {
return new ConfigLoader(dataDirectory, configClass, producer, cipher);
}
@Provides
@Singleton
public FloodgateHandshakeHandler handshakeHandler(

View File

@@ -27,11 +27,12 @@ package org.geysermc.floodgate.module;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import java.util.List;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public final class PostEnableModules extends AbstractModule {
private final Module[] postInitializeModules;
private final List<Module> postInitializeModules;
@Override
protected void configure() {

View File

@@ -44,7 +44,6 @@ public final class ProxyCommonModule extends CommonModule {
super.configure();
bind(SimpleFloodgateApi.class).to(ProxyFloodgateApi.class);
bind(ProxyFloodgateApi.class).in(Singleton.class);
}
@Provides

View File

@@ -29,7 +29,6 @@ import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import java.nio.file.Path;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.config.FloodgateConfig;
public final class ServerCommonModule extends CommonModule {
@@ -37,12 +36,6 @@ public final class ServerCommonModule extends CommonModule {
super(dataDirectory);
}
@Override
protected void configure() {
super.configure();
bind(SimpleFloodgateApi.class).in(Singleton.class);
}
@Provides
@Singleton
@Named("configClass")

View File

@@ -28,7 +28,6 @@ package org.geysermc.floodgate.player;
import java.net.InetSocketAddress;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -40,14 +39,14 @@ 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.api.handshake.HandshakeData;
import org.geysermc.floodgate.api.legacy.PropertyGlue;
import org.geysermc.floodgate.util.BedrockData;
import org.geysermc.floodgate.util.LinkedPlayer;
import org.geysermc.floodgate.util.Utils;
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
public final class FloodgatePlayerImpl implements Connection {
public final class FloodgateConnection implements Connection {
private final String version;
private final String username;
private final String javaUsername;
@@ -66,7 +65,9 @@ public final class FloodgatePlayerImpl implements Connection {
private final InetSocketAddress socketAddress;
static FloodgatePlayerImpl from(BedrockData data, HandshakeDataImpl handshakeData, int port) {
private final PropertyGlue propertyGlue = new PropertyGlue();
static FloodgateConnection from(BedrockData data, HandshakeData handshakeData, int port) {
UUID javaUniqueId = Utils.getJavaUuid(data.getXuid());
BedrockPlatform deviceOs = BedrockPlatform.fromId(data.getDeviceOs());
@@ -77,7 +78,7 @@ public final class FloodgatePlayerImpl implements Connection {
InetSocketAddress socketAddress = new InetSocketAddress(data.getIp(), port);
return new FloodgatePlayerImpl(
return new FloodgateConnection(
data.getVersion(), data.getUsername(), handshakeData.getJavaUsername(),
javaUniqueId, data.getXuid(), deviceOs, data.getLanguageCode(), uiProfile,
inputMode, data.getIp(), data.isFromProxy(),
@@ -150,7 +151,7 @@ public final class FloodgatePlayerImpl implements Connection {
}
@Override
public InetSocketAddress socketAddress() {
public @NonNull InetSocketAddress socketAddress() {
return socketAddress;
}
@@ -159,4 +160,8 @@ public final class FloodgatePlayerImpl implements Connection {
uiProfile.ordinal(), inputMode.ordinal(), ip, linkedPlayer, proxy, subscribeId,
verifyCode);
}
public PropertyGlue propertyGlue() {
return propertyGlue;
}
}

View File

@@ -205,7 +205,7 @@ public final class FloodgateHandshakeHandler {
LinkedPlayer linkedPlayer) {
try {
HandshakeDataImpl handshakeData = new HandshakeDataImpl(
HandshakeData handshakeData = new HandshakeDataImpl(
channel, true, bedrockData.clone(), config,
linkedPlayer != null ? linkedPlayer.clone() : null, hostname);
@@ -222,7 +222,7 @@ public final class FloodgateHandshakeHandler {
int port = ((InetSocketAddress) channel.remoteAddress()).getPort();
Connection player = FloodgatePlayerImpl.from(bedrockData, handshakeData, port);
Connection player = FloodgateConnection.from(bedrockData, handshakeData, port);
api.addPlayer(player);

View File

@@ -35,6 +35,8 @@ import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.Set;
@@ -160,6 +162,7 @@ public class Utils {
* @param input the fully qualified name of the annotation
* @return a set of all the classes annotated by the given annotation
*/
@SuppressWarnings("ConstantConditions")
public static Set<Class<?>> getGeneratedClassesForAnnotation(String input) {
try (InputStream annotatedClass = Utils.class.getClassLoader().getResourceAsStream(input);
BufferedReader reader = new BufferedReader(new InputStreamReader(annotatedClass))) {
@@ -174,4 +177,13 @@ public class Utils {
throw new RuntimeException(e);
}
}
@SuppressWarnings({"ManualArrayToCollectionCopy", "UseBulkOperation"})
public static <T> List<T> asList(T... data) {
List<T> list = new ArrayList<>(data.length);
for (T entry : data) {
list.add(entry);
}
return list;
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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.util;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.concurrent.CompletableFuture;
@Singleton
public class WebEndpoints {
@Inject
private HttpClient httpClient;
public CompletableFuture<Long> getXuidFor(String gamertag) {
if (gamertag == null || gamertag.isEmpty() || gamertag.length() > 16) {
return Utils.failedFuture(new IllegalStateException("Received an invalid gamertag"));
}
return httpClient.asyncGet(Constants.GET_XUID_URL + gamertag)
.thenApply(result -> {
JsonObject response = result.getResponse();
if (!result.isCodeOk()) {
throw new IllegalStateException(response.get("message").getAsString());
}
JsonElement xuid = response.get("xuid");
return xuid != null ? xuid.getAsLong() : null;
});
}
public CompletableFuture<String> getGamertagFor(long xuid) {
return httpClient.asyncGet(Constants.GET_GAMERTAG_URL + xuid)
.thenApply(result -> {
JsonObject response = result.getResponse();
if (!result.isCodeOk()) {
throw new IllegalStateException(response.get("message").getAsString());
}
JsonElement gamertag = response.get("gamertag");
return gamertag != null ? gamertag.getAsString() : null;
});
}
}

View File

@@ -1,4 +1,4 @@
>> config.yml
>> floodgate-config.yml
>>| 16
# Should the proxy send the bedrock player data to the servers it is connecting to?
# This requires Floodgate to be installed on the servers.