diff --git a/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java
index 7df084ab..7cc38c55 100644
--- a/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java
+++ b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java
@@ -26,6 +26,7 @@
package org.geysermc.floodgate.api;
import java.util.UUID;
+import org.geysermc.common.form.Form;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
@@ -71,6 +72,8 @@ public interface FloodgateApi {
*/
boolean isFloodgateId(UUID uuid);
+ boolean sendForm(UUID uuid, Form form);
+
/**
* Returns the instance that manages all the linking.
*/
diff --git a/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java b/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java
index 41796821..73bb823e 100644
--- a/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java
+++ b/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java
@@ -26,6 +26,8 @@
package org.geysermc.floodgate.api.player;
import java.util.UUID;
+import org.geysermc.common.form.Form;
+import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.util.DeviceOs;
import org.geysermc.floodgate.util.InputMode;
import org.geysermc.floodgate.util.LinkedPlayer;
@@ -104,6 +106,10 @@ public interface FloodgatePlayer {
*/
RawSkin getRawSkin();
+ default boolean sendForm(Form form) {
+ return FloodgateApi.getInstance().sendForm(getCorrectUniqueId(), form);
+ }
+
/**
* Casts the FloodgatePlayer instance to a class that extends FloodgatePlayer.
*
diff --git a/bungee/src/main/java/org/geysermc/floodgate/handler/BungeeDataHandler.java b/bungee/src/main/java/org/geysermc/floodgate/handler/BungeeDataHandler.java
index 8bc136ce..eabb4acb 100644
--- a/bungee/src/main/java/org/geysermc/floodgate/handler/BungeeDataHandler.java
+++ b/bungee/src/main/java/org/geysermc/floodgate/handler/BungeeDataHandler.java
@@ -35,6 +35,7 @@ import io.netty.util.AttributeKey;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
+import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PreLoginEvent;
import net.md_5.bungee.api.plugin.Plugin;
@@ -102,10 +103,10 @@ public final class BungeeDataHandler {
event.setCancelReason(config.getMessages().getInvalidKey());
break;
case INVALID_DATA_LENGTH:
- event.setCancelReason(String.format(
+ event.setCancelReason(TextComponent.fromLegacyText(String.format(
config.getMessages().getInvalidArgumentsLength(),
BedrockData.EXPECTED_LENGTH, result.getBedrockData().getDataLength()
- ));
+ )));
break;
}
@@ -131,9 +132,6 @@ public final class BungeeDataHandler {
SocketAddress remoteAddress =
ReflectionUtils.getCastedValue(channelWrapper, PLAYER_REMOTE_ADDRESS);
- Channel channel = ReflectionUtils.getCastedValue(channelWrapper, PLAYER_CHANNEL);
- channel.attr(playerAttribute).set(player);
-
if (!(remoteAddress instanceof InetSocketAddress)) {
logger.info("Player {} doesn't use an InetSocketAddress, it uses {}. " +
"Ignoring the player, I guess.",
@@ -146,6 +144,11 @@ public final class BungeeDataHandler {
new InetSocketAddress(result.getBedrockData().getIp(), port)
);
}
+
+ Channel channel = ReflectionUtils.getCastedValue(channelWrapper, PLAYER_CHANNEL);
+
+ channel.attr(playerAttribute).set(player);
+
event.completeIntent(plugin);
});
}
diff --git a/bungee/src/main/java/org/geysermc/floodgate/module/BungeeListenerModule.java b/bungee/src/main/java/org/geysermc/floodgate/module/BungeeListenerModule.java
index 370479de..6f57739e 100644
--- a/bungee/src/main/java/org/geysermc/floodgate/module/BungeeListenerModule.java
+++ b/bungee/src/main/java/org/geysermc/floodgate/module/BungeeListenerModule.java
@@ -31,6 +31,7 @@ import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.ProvidesIntoSet;
import net.md_5.bungee.api.plugin.Listener;
import org.geysermc.floodgate.listener.BungeeListener;
+import org.geysermc.floodgate.platform.pluginmessage.PluginMessageHandler;
import org.geysermc.floodgate.register.ListenerRegister;
public final class BungeeListenerModule extends AbstractModule {
@@ -44,4 +45,10 @@ public final class BungeeListenerModule extends AbstractModule {
public Listener bungeeListener() {
return new BungeeListener();
}
+
+ @Singleton
+ @ProvidesIntoSet
+ public Listener pluginMessageListener(PluginMessageHandler handler) {
+ return (Listener) handler; // Plugin message handler is also the listener
+ }
}
diff --git a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java
index e80fbd71..88a59916 100644
--- a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java
+++ b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java
@@ -47,6 +47,8 @@ import org.geysermc.floodgate.logger.JavaUtilFloodgateLogger;
import org.geysermc.floodgate.platform.command.CommandRegistration;
import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.platform.listener.ListenerRegistration;
+import org.geysermc.floodgate.platform.pluginmessage.PluginMessageHandler;
+import org.geysermc.floodgate.pluginmessage.BungeePluginMessageHandler;
import org.geysermc.floodgate.util.BungeeCommandUtil;
import org.geysermc.floodgate.util.LanguageManager;
@@ -74,8 +76,9 @@ public final class BungeePlatformModule extends AbstractModule {
@Provides
@Singleton
- public ProxyFloodgateApi proxyFloodgateApi(FloodgateCipher cipher) {
- return new ProxyFloodgateApi(cipher);
+ public ProxyFloodgateApi proxyFloodgateApi(PluginMessageHandler pluginMessageHandler,
+ FloodgateCipher cipher) {
+ return new ProxyFloodgateApi(pluginMessageHandler, cipher);
}
@Provides
@@ -107,6 +110,12 @@ public final class BungeePlatformModule extends AbstractModule {
return new BungeeListenerRegistration(plugin);
}
+ @Provides
+ @Singleton
+ public PluginMessageHandler pluginMessageHandler() {
+ return new BungeePluginMessageHandler();
+ }
+
/*
DebugAddon / PlatformInjector
*/
diff --git a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeePluginMessageHandler.java b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeePluginMessageHandler.java
new file mode 100644
index 00000000..fe734e52
--- /dev/null
+++ b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeePluginMessageHandler.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2019-2020 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.pluginmessage;
+
+import static org.geysermc.floodgate.util.MessageFormatter.format;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import java.util.UUID;
+import net.md_5.bungee.api.ProxyServer;
+import net.md_5.bungee.api.chat.TextComponent;
+import net.md_5.bungee.api.connection.Connection;
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+import net.md_5.bungee.api.connection.Server;
+import net.md_5.bungee.api.event.PluginMessageEvent;
+import net.md_5.bungee.api.plugin.Listener;
+import net.md_5.bungee.api.plugin.Plugin;
+import net.md_5.bungee.event.EventHandler;
+import org.geysermc.common.form.Form;
+import org.geysermc.floodgate.api.logger.FloodgateLogger;
+import org.geysermc.floodgate.platform.pluginmessage.PluginMessageHandler;
+
+public class BungeePluginMessageHandler extends PluginMessageHandler implements Listener {
+ private ProxyServer proxy;
+ private FloodgateLogger logger;
+ private String formChannel;
+
+ @Inject // called because this is a listener as well
+ public void init(Plugin plugin, FloodgateLogger logger,
+ @Named("formChannel") String formChannel,
+ @Named("skinChannel") String skinChannel) {
+ super.proxy = true;
+ this.proxy = plugin.getProxy();
+ this.logger = logger;
+ this.formChannel = formChannel;
+
+ proxy.registerChannel(formChannel);
+ proxy.registerChannel(skinChannel);
+ }
+
+ @EventHandler
+ public void onPluginMessage(PluginMessageEvent event) {
+ Connection source = event.getSender();
+ if (event.getTag().equals(formChannel)) {
+ if (source instanceof Server) {
+ // send it to the client
+ event.setCancelled(false);
+ return;
+ }
+
+ if (source instanceof ProxiedPlayer) {
+ byte[] data = event.getData();
+ if (data.length < 2) {
+ logger.error("Invalid form response! Closing connection");
+ source.disconnect(new TextComponent("Invalid form response!"));
+ return;
+ }
+
+ short formId = getFormId(data);
+
+ // if the bit is not set, it's for the connected server
+ if ((formId & 0x8000) == 0) {
+ event.setCancelled(false);
+ return;
+ }
+
+ event.setCancelled(true);
+
+ if (!callResponseConsumer(data)) {
+ logger.error(format(
+ "Couldn't find stored form with id {} for player {}",
+ formId, ((ProxiedPlayer) source).getName()));
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean sendForm(UUID uuid, Form form) {
+ ProxiedPlayer player = proxy.getPlayer(uuid);
+ if (player != null) {
+ player.sendData(formChannel, createFormData(form));
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/common/pom.xml b/common/pom.xml
index b803f004..0b92f849 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -53,6 +53,17 @@
jackson-dataformat-yaml
2.9.9
+
+ com.nukkitx.fastutil
+ fastutil-short-object-maps
+ 8.3.1
+ compile
+
+
+
+
+
+
4.0.0
@@ -84,5 +95,10 @@
true
+
+ minecraft-libraries
+ Minecraft Libraries
+ https://libraries.minecraft.net
+
\ No newline at end of file
diff --git a/common/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java b/common/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java
index b778dcf0..3e86f14b 100644
--- a/common/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java
+++ b/common/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java
@@ -111,7 +111,7 @@ public class FloodgatePlatform {
return false;
}
- guice.createChildInjector(new PostInitializeModule(postInitializeModules));
+ this.guice = guice.createChildInjector(new PostInitializeModule(postInitializeModules));
return true;
}
diff --git a/common/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java b/common/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java
index 7b9b9a83..f11094bb 100644
--- a/common/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java
+++ b/common/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java
@@ -30,12 +30,15 @@ import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
import lombok.RequiredArgsConstructor;
+import org.geysermc.common.form.Form;
import org.geysermc.floodgate.FloodgatePlayerImpl;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
+import org.geysermc.floodgate.platform.pluginmessage.PluginMessageHandler;
@RequiredArgsConstructor
public class SimpleFloodgateApi implements FloodgateApi {
private final Map players = new HashMap<>();
+ private final PluginMessageHandler pluginMessageHandler;
@Override
public boolean isBedrockPlayer(UUID uuid) {
@@ -70,6 +73,13 @@ public class SimpleFloodgateApi implements FloodgateApi {
return uuid.getMostSignificantBits() == 0;
}
+ @Override
+ public boolean sendForm(UUID uuid, Form form) {
+ // the most easy way is to add the sendForm method to something that has to be implemented
+ // to every platform anyway, not the most elegant solution though.
+ return pluginMessageHandler.sendForm(uuid, form);
+ }
+
public FloodgatePlayer addPlayer(UUID uuid, FloodgatePlayer player) {
return players.put(uuid, player);
}
diff --git a/common/src/main/java/org/geysermc/floodgate/command/CommonCommandMessage.java b/common/src/main/java/org/geysermc/floodgate/command/CommonCommandMessage.java
index 26b0f499..545047b4 100644
--- a/common/src/main/java/org/geysermc/floodgate/command/CommonCommandMessage.java
+++ b/common/src/main/java/org/geysermc/floodgate/command/CommonCommandMessage.java
@@ -33,6 +33,7 @@ import org.geysermc.floodgate.platform.command.CommandMessage;
*/
public enum CommonCommandMessage implements CommandMessage {
NOT_A_PLAYER("floodgate.commands.not_a_player"),
+ NO_PERMISSION("floodgate.commands.no_permission"),
CHECK_CONSOLE("floodgate.commands.check_console"),
// TODO used to also have console check
IS_LINKED_ERROR("floodgate.commands.is_linked_error");
diff --git a/common/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java b/common/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java
index 0daf65a0..be201811 100644
--- a/common/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java
+++ b/common/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java
@@ -47,6 +47,17 @@ public final class LinkAccountCommand implements Command {
@Inject private FloodgateApi api;
@Inject private CommandUtil commandUtil;
+// @Override todo impl this
+// public LiteralCommandNode commandNode(T source, CommandUtil commandUtil) {
+// return literal(getName())
+// .then(
+// argument("gamertag", word())
+// .executes(cmd -> {
+// return 0;
+// })
+// ).build();
+// }
+
@Override
public void execute(Object player, UUID uuid, String username, String locale, String[] args) {
PlayerLink link = api.getPlayerLink();
@@ -134,6 +145,11 @@ public final class LinkAccountCommand implements Command {
return "linkaccount";
}
+ @Override
+ public String getDescription() {
+ return "Link your Java account with your Bedrock account";
+ }
+
@Override
public String getPermission() {
return "floodgate.linkaccount";
diff --git a/common/src/main/java/org/geysermc/floodgate/command/UnlinkAccountCommand.java b/common/src/main/java/org/geysermc/floodgate/command/UnlinkAccountCommand.java
index 86edb15d..eda3c621 100644
--- a/common/src/main/java/org/geysermc/floodgate/command/UnlinkAccountCommand.java
+++ b/common/src/main/java/org/geysermc/floodgate/command/UnlinkAccountCommand.java
@@ -77,6 +77,11 @@ public final class UnlinkAccountCommand implements Command {
return "unlinkaccount";
}
+ @Override
+ public String getDescription() {
+ return "Unlink your Java account from your Bedrock account";
+ }
+
@Override
public String getPermission() {
return "floodgate.unlinkaccount";
diff --git a/common/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/common/src/main/java/org/geysermc/floodgate/module/CommonModule.java
index de575dcc..6bcf3edc 100644
--- a/common/src/main/java/org/geysermc/floodgate/module/CommonModule.java
+++ b/common/src/main/java/org/geysermc/floodgate/module/CommonModule.java
@@ -101,8 +101,8 @@ public final class CommonModule extends AbstractModule {
@Provides
@Singleton
- public LanguageManager languageLoader(FloodgateLogger logger) {
- return new LanguageManager(logger);
+ public LanguageManager languageLoader() {
+ return new LanguageManager();
}
@Provides
@@ -123,4 +123,18 @@ public final class CommonModule extends AbstractModule {
public AttributeKey playerAttribute() {
return AttributeKey.newInstance("floodgate-player");
}
+
+ @Provides
+ @Singleton
+ @Named("formChannel")
+ public String formChannel() {
+ return "floodgate:form";
+ }
+
+ @Provides
+ @Singleton
+ @Named("skinChannel")
+ public String skinChannel() {
+ return "floodgate:skin";
+ }
}
diff --git a/common/src/main/java/org/geysermc/floodgate/platform/command/Command.java b/common/src/main/java/org/geysermc/floodgate/platform/command/Command.java
index 338c5134..c3b0e4b7 100644
--- a/common/src/main/java/org/geysermc/floodgate/platform/command/Command.java
+++ b/common/src/main/java/org/geysermc/floodgate/platform/command/Command.java
@@ -31,6 +31,8 @@ import java.util.UUID;
* The base class for every Floodgate command.
*/
public interface Command {
+// LiteralCommandNode commandNode(T source, CommandUtil commandUtil);
+
/**
* Should be implemented when {@link #isRequirePlayer()} is true or when the source is a
* player.
@@ -68,6 +70,12 @@ public interface Command {
*/
String getName();
+ /**
+ * Description of the command. Used as description in commands like /help (Spigot) and when you
+ * run the command without any arguments
+ */
+ String getDescription();
+
/**
* The permission that is required to execute the specific command. Should return null when
* there is no permission required.
diff --git a/common/src/main/java/org/geysermc/floodgate/platform/pluginmessage/PluginMessageHandler.java b/common/src/main/java/org/geysermc/floodgate/platform/pluginmessage/PluginMessageHandler.java
new file mode 100644
index 00000000..0b1e448b
--- /dev/null
+++ b/common/src/main/java/org/geysermc/floodgate/platform/pluginmessage/PluginMessageHandler.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019-2020 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.platform.pluginmessage;
+
+import com.google.common.base.Charsets;
+import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
+import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.geysermc.common.form.Form;
+
+public abstract class PluginMessageHandler {
+ protected final Short2ObjectMap