mirror of
https://github.com/GeyserMC/Floodgate.git
synced 2025-12-19 14:59:20 +00:00
Added support for Forms and changed Commands + the LanguageManager a bit
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,17 @@
|
||||
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||
<version>2.9.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-short-object-maps</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- <dependency> todo -->
|
||||
<!-- <groupId>com.mojang</groupId>-->
|
||||
<!-- <artifactId>brigadier</artifactId>-->
|
||||
<!-- <version>1.0.17</version>-->
|
||||
<!-- </dependency>-->
|
||||
</dependencies>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -84,5 +95,10 @@
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>minecraft-libraries</id>
|
||||
<name>Minecraft Libraries</name>
|
||||
<url>https://libraries.minecraft.net</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
@@ -111,7 +111,7 @@ public class FloodgatePlatform {
|
||||
return false;
|
||||
}
|
||||
|
||||
guice.createChildInjector(new PostInitializeModule(postInitializeModules));
|
||||
this.guice = guice.createChildInjector(new PostInitializeModule(postInitializeModules));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<UUID, FloodgatePlayer> 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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -47,6 +47,17 @@ public final class LinkAccountCommand implements Command {
|
||||
@Inject private FloodgateApi api;
|
||||
@Inject private CommandUtil commandUtil;
|
||||
|
||||
// @Override todo impl this
|
||||
// public <T> LiteralCommandNode<T> 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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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<FloodgatePlayer> 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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ import java.util.UUID;
|
||||
* The base class for every Floodgate command.
|
||||
*/
|
||||
public interface Command {
|
||||
// <T> LiteralCommandNode<T> 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.
|
||||
|
||||
@@ -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<Form> storedForms = new Short2ObjectOpenHashMap<>();
|
||||
private final AtomicInteger nextFormId = new AtomicInteger(0);
|
||||
protected boolean proxy = false;
|
||||
|
||||
public abstract boolean sendForm(UUID player, Form form);
|
||||
|
||||
protected byte[] createFormData(Form form) {
|
||||
short formId = getNextFormId();
|
||||
if (proxy) {
|
||||
formId |= 0x8000;
|
||||
}
|
||||
storedForms.put(formId, form);
|
||||
|
||||
byte[] jsonData = form.getJsonData().getBytes(Charsets.UTF_8);
|
||||
|
||||
byte[] data = new byte[jsonData.length + 3];
|
||||
data[0] = (byte) form.getType().ordinal();
|
||||
data[1] = (byte) (formId >> 8 & 0xFF);
|
||||
data[2] = (byte) (formId & 0xFF);
|
||||
System.arraycopy(jsonData, 0, data, 3, jsonData.length);
|
||||
return data;
|
||||
}
|
||||
|
||||
protected boolean callResponseConsumer(byte[] data) {
|
||||
Form storedForm = storedForms.remove(getFormId(data));
|
||||
if (storedForm != null) {
|
||||
storedForm.getResponseHandler().accept(
|
||||
new String(data, 2, data.length - 2, Charsets.UTF_8));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected short getFormId(byte[] data) {
|
||||
return (short) ((data[0] & 0xFF) << 8 | data[1] & 0xFF);
|
||||
}
|
||||
|
||||
protected short getNextFormId() {
|
||||
// signed bit is used to check if the form is from a proxy or a server
|
||||
return (short) nextFormId.getAndUpdate(
|
||||
(number) -> number == Short.MAX_VALUE ? 0 : number + 1);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package org.geysermc.floodgate.util;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -47,13 +48,17 @@ import org.geysermc.floodgate.config.FloodgateConfig;
|
||||
public final class LanguageManager {
|
||||
private final Map<String, Properties> LOCALE_MAPPINGS = new HashMap<>();
|
||||
|
||||
private final FloodgateLogger logger;
|
||||
|
||||
/**
|
||||
* The locale used in console and as a fallback
|
||||
*/
|
||||
@Getter private String defaultLocale;
|
||||
|
||||
@Inject private FloodgateLogger logger;
|
||||
|
||||
public boolean isLoaded() {
|
||||
return logger != null && defaultLocale != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up and formats a locale string
|
||||
*
|
||||
@@ -76,24 +81,30 @@ public final class LanguageManager {
|
||||
*/
|
||||
@Inject
|
||||
public void init(FloodgateConfig config) {
|
||||
loadLocale("en_US"); // Fallback
|
||||
if (!loadLocale("en_US")) {// Fallback
|
||||
logger.error("Failed to load the fallback language. This will likely cause errors!");
|
||||
}
|
||||
|
||||
defaultLocale = formatLocale(config.getDefaultLocale());
|
||||
|
||||
if (isValidLanguage(defaultLocale)) {
|
||||
loadLocale(defaultLocale);
|
||||
if (loadLocale(defaultLocale)) {
|
||||
return;
|
||||
}
|
||||
logger.warn("Language provided in the config wasn't found. Will use system locale.");
|
||||
}
|
||||
|
||||
String systemLocale = formatLocale(
|
||||
Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry()
|
||||
);
|
||||
|
||||
if (isValidLanguage(systemLocale)) {
|
||||
loadLocale(systemLocale);
|
||||
if (loadLocale(systemLocale)) {
|
||||
defaultLocale = systemLocale;
|
||||
return;
|
||||
}
|
||||
logger.warn("Language file for system locale wasn't found. Falling back to en_US");
|
||||
}
|
||||
|
||||
defaultLocale = "en_US";
|
||||
}
|
||||
@@ -102,19 +113,20 @@ public final class LanguageManager {
|
||||
* Loads a Floodgate locale from resources; if the file doesn't exist it just logs a warning
|
||||
*
|
||||
* @param locale locale to load
|
||||
* @return true if the locale has been found
|
||||
*/
|
||||
public void loadLocale(String locale) {
|
||||
public boolean loadLocale(String locale) {
|
||||
locale = formatLocale(locale);
|
||||
|
||||
// just return if the locale has been loaded already
|
||||
if (LOCALE_MAPPINGS.containsKey(locale)) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
InputStream localeStream = LanguageManager.class.getClassLoader().getResourceAsStream(
|
||||
"languages/texts/" + locale + ".properties");
|
||||
|
||||
// Load the locale
|
||||
// load the locale
|
||||
if (localeStream != null) {
|
||||
Properties localeProp = new Properties();
|
||||
try {
|
||||
@@ -123,11 +135,13 @@ public final class LanguageManager {
|
||||
throw new AssertionError("Failed to load Floodgate locale", e);
|
||||
}
|
||||
|
||||
// Insert the locale into the mappings
|
||||
// insert the locale into the mappings
|
||||
LOCALE_MAPPINGS.put(locale, localeProp);
|
||||
} else {
|
||||
logger.warn("Missing locale file: " + locale);
|
||||
return true;
|
||||
}
|
||||
|
||||
logger.warn("Missing locale file: " + locale);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,7 +149,7 @@ public final class LanguageManager {
|
||||
*
|
||||
* @param key language string to translate
|
||||
* @param values values to put into the string
|
||||
* @return translated string or the original message if it was not found in the given locale
|
||||
* @return translated string or "key arg1, arg2 (etc.)" if it was not found in the given locale
|
||||
*/
|
||||
public String getLogString(String key, Object... values) {
|
||||
return getString(key, defaultLocale, values);
|
||||
@@ -147,31 +161,33 @@ public final class LanguageManager {
|
||||
* @param key language string to translate
|
||||
* @param locale locale to translate to
|
||||
* @param values values to put into the string
|
||||
* @return translated string or the original message if it was not found in the given locale
|
||||
* @return translated string or "key arg1, arg2 (etc.)" if it was not found in the given locale
|
||||
*/
|
||||
public String getString(String key, String locale, Object... values) {
|
||||
locale = formatLocale(locale);
|
||||
// we can skip everything if the LanguageManager isn't loaded yet
|
||||
if (!isLoaded()) {
|
||||
return formatNotFound(key, values);
|
||||
}
|
||||
|
||||
Properties properties = LOCALE_MAPPINGS.get(locale);
|
||||
String formatString = properties.getProperty(key);
|
||||
String formatString = null;
|
||||
|
||||
// Try and get the key from the default locale
|
||||
if (properties != null) {
|
||||
formatString = properties.getProperty(key);
|
||||
}
|
||||
|
||||
// try and get the key from the default locale
|
||||
if (formatString == null) {
|
||||
properties = LOCALE_MAPPINGS.get(defaultLocale);
|
||||
formatString = properties.getProperty(key);
|
||||
}
|
||||
|
||||
// Try and get the key from en_US (this should only ever happen in development)
|
||||
// key wasn't found
|
||||
if (formatString == null) {
|
||||
properties = LOCALE_MAPPINGS.get("en_US");
|
||||
formatString = properties.getProperty(key);
|
||||
}
|
||||
|
||||
// Final fallback
|
||||
if (formatString == null) {
|
||||
formatString = key;
|
||||
return formatNotFound(key, values);
|
||||
}
|
||||
|
||||
//todo don't use color codes in the strings
|
||||
return MessageFormat.format(formatString.replace("'", "''").replace("&", "\u00a7"), values);
|
||||
}
|
||||
|
||||
@@ -195,4 +211,8 @@ public final class LanguageManager {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String formatNotFound(String key, Object... args) {
|
||||
return key + " " + Joiner.on(", ").join(args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,18 @@ public final class ReflectionUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the given field by finding the field and then get the value of it.
|
||||
*
|
||||
* @param instance the instance of the object
|
||||
* @param fieldName the name of the field to get the value from
|
||||
* @return the value of the field when succeeded, otheriwse null
|
||||
*/
|
||||
@Nullable
|
||||
public static Object getValue(Object instance, String fieldName) {
|
||||
return getValue(instance, getField(instance.getClass(), fieldName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a field and cast it to <T>.
|
||||
*
|
||||
@@ -226,15 +238,17 @@ public final class ReflectionUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the given field by finding the field and then get the value of it.
|
||||
* Get the value of a field and cast it to <T>.
|
||||
*
|
||||
* @param instance the instance of the object
|
||||
* @param fieldName the name of the field to get the value from
|
||||
* @return the value of the field when succeeded, otheriwse null
|
||||
* @param instance the instance to get the value from
|
||||
* @param fieldName the field to get the value from
|
||||
* @param <T> the type to cast the value to
|
||||
* @return the casted value when succeeded, otherwise null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
public static Object getValue(Object instance, String fieldName) {
|
||||
return getValue(instance, getField(instance.getClass(), fieldName));
|
||||
public static <T> T getCastedValue(Object instance, String fieldName) {
|
||||
return (T) getValue(instance, getField(instance.getClass(), fieldName));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -47,7 +47,7 @@
|
||||
<geyser.version>1.1.0</geyser.version>
|
||||
<spigot.version>1.8.8-R0.1-SNAPSHOT</spigot.version>
|
||||
<bungee.version>1.15-SNAPSHOT</bungee.version>
|
||||
<velocity.version>1.1.0-SNAPSHOT</velocity.version>
|
||||
<velocity.version>1.1.0</velocity.version>
|
||||
|
||||
<outputName>floodgate-${project.name}</outputName>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
@@ -25,56 +25,74 @@
|
||||
|
||||
package org.geysermc.floodgate.command;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import java.util.Collections;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandException;
|
||||
import org.bukkit.command.CommandMap;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.geysermc.floodgate.platform.command.Command;
|
||||
import org.geysermc.floodgate.platform.command.CommandRegistration;
|
||||
import org.geysermc.floodgate.platform.command.CommandUtil;
|
||||
import org.geysermc.floodgate.util.LanguageManager;
|
||||
import org.geysermc.floodgate.util.ReflectionUtils;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class SpigotCommandRegistration implements CommandRegistration {
|
||||
private final JavaPlugin plugin;
|
||||
private final CommandUtil commandUtil;
|
||||
private final LanguageManager languageManager;
|
||||
private final CommandMap commandMap;
|
||||
|
||||
public SpigotCommandRegistration(JavaPlugin plugin, CommandUtil commandUtil) {
|
||||
this.plugin = plugin;
|
||||
this.commandUtil = commandUtil;
|
||||
this.commandMap = ReflectionUtils.getCastedValue(Bukkit.getPluginManager(), "commandMap");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Command command) {
|
||||
String defaultLocale = languageManager.getDefaultLocale();
|
||||
|
||||
plugin.getCommand(command.getName())
|
||||
.setExecutor(new SpigotCommandWrapper(commandUtil, command, defaultLocale));
|
||||
commandMap.register("floodgate", new SpigotCommand(plugin, commandUtil, command));
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
protected static class SpigotCommandWrapper implements CommandExecutor {
|
||||
protected static class SpigotCommand extends org.bukkit.command.Command {
|
||||
private final JavaPlugin plugin;
|
||||
private final CommandUtil commandUtil;
|
||||
private final Command command;
|
||||
private final String defaultLocale;
|
||||
|
||||
protected SpigotCommand(JavaPlugin plugin, CommandUtil commandUtil, Command command) {
|
||||
super(command.getName(), command.getDescription(), "", Collections.emptyList());
|
||||
this.plugin = plugin;
|
||||
this.commandUtil = commandUtil;
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender source, org.bukkit.command.Command cmd,
|
||||
String label, String[] args) {
|
||||
if (!(source instanceof Player)) {
|
||||
if (command.isRequirePlayer()) {
|
||||
commandUtil.sendMessage(
|
||||
source, defaultLocale,
|
||||
CommonCommandMessage.NOT_A_PLAYER
|
||||
);
|
||||
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new CommandException("Cannot execute command '" + commandLabel +
|
||||
"' while the plugin is disabled");
|
||||
}
|
||||
if (!sender.hasPermission(command.getPermission())) {
|
||||
commandUtil.sendMessage(sender, null, CommonCommandMessage.NO_PERMISSION);
|
||||
return true;
|
||||
}
|
||||
command.execute(source, defaultLocale, args);
|
||||
executeCommand(sender, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
Player player = (Player) source;
|
||||
public void executeCommand(CommandSender sender, String[] args) {
|
||||
if (!(sender instanceof Player)) {
|
||||
if (command.isRequirePlayer()) {
|
||||
commandUtil.sendMessage(sender, null, CommonCommandMessage.NOT_A_PLAYER);
|
||||
return;
|
||||
}
|
||||
command.execute(sender, null, args);
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = (Player) sender;
|
||||
String locale = player.spigot().getLocale();
|
||||
|
||||
command.execute(source, player.getUniqueId(), source.getName(), locale, args);
|
||||
return true;
|
||||
command.execute(sender, player.getUniqueId(), sender.getName(), locale, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +42,10 @@ import org.geysermc.floodgate.inject.spigot.SpigotInjector;
|
||||
import org.geysermc.floodgate.listener.SpigotListenerRegistration;
|
||||
import org.geysermc.floodgate.logger.JavaUtilFloodgateLogger;
|
||||
import org.geysermc.floodgate.platform.command.CommandRegistration;
|
||||
import org.geysermc.floodgate.platform.listener.ListenerRegistration;
|
||||
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.BukkitPluginMessageHandler;
|
||||
import org.geysermc.floodgate.util.LanguageManager;
|
||||
import org.geysermc.floodgate.util.SpigotCommandUtil;
|
||||
|
||||
@@ -66,8 +68,8 @@ public final class SpigotPlatformModule extends AbstractModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public SimpleFloodgateApi floodgateApi() {
|
||||
return new SimpleFloodgateApi();
|
||||
public SimpleFloodgateApi floodgateApi(PluginMessageHandler pluginMessageHandler) {
|
||||
return new SimpleFloodgateApi(pluginMessageHandler);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -82,9 +84,8 @@ public final class SpigotPlatformModule extends AbstractModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public CommandRegistration commandRegistration(CommandUtil commandUtil,
|
||||
LanguageManager languageManager) {
|
||||
return new SpigotCommandRegistration(plugin, commandUtil, languageManager);
|
||||
public CommandRegistration commandRegistration(CommandUtil commandUtil) {
|
||||
return new SpigotCommandRegistration(plugin, commandUtil);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -99,6 +100,13 @@ public final class SpigotPlatformModule extends AbstractModule {
|
||||
return new SpigotListenerRegistration(plugin);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public PluginMessageHandler pluginMessageHandler(@Named("formChannel") String formChannel,
|
||||
@Named("skinChannel") String skinChannel) {
|
||||
return new BukkitPluginMessageHandler(plugin, formChannel, skinChannel);
|
||||
}
|
||||
|
||||
/*
|
||||
DebugAddon / PlatformInjector
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.messaging.Messenger;
|
||||
import org.geysermc.common.form.Form;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
import org.geysermc.floodgate.platform.pluginmessage.PluginMessageHandler;
|
||||
import org.geysermc.floodgate.util.ReflectionUtils;
|
||||
|
||||
public class BukkitPluginMessageHandler extends PluginMessageHandler {
|
||||
private final JavaPlugin plugin;
|
||||
private final String formChannel;
|
||||
private final String skinChannel;
|
||||
|
||||
public BukkitPluginMessageHandler(JavaPlugin plugin, String formChannel, String skinChannel) {
|
||||
this.plugin = plugin;
|
||||
this.formChannel = formChannel;
|
||||
this.skinChannel = skinChannel;
|
||||
|
||||
Messenger messenger = plugin.getServer().getMessenger();
|
||||
|
||||
// form
|
||||
messenger.registerIncomingPluginChannel(
|
||||
plugin, formChannel,
|
||||
(channel, player, message) -> callResponseConsumer(message));
|
||||
messenger.registerOutgoingPluginChannel(plugin, formChannel);
|
||||
|
||||
// skin
|
||||
messenger.registerIncomingPluginChannel(
|
||||
plugin, skinChannel,
|
||||
(channel, player, message) -> {
|
||||
String origin =
|
||||
FloodgateApi.getInstance().getPlayer(player.getUniqueId()) != null
|
||||
? "Geyser" : "player";
|
||||
System.out.println("Got skin from " + origin + "!");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendForm(UUID playerId, Form form) {
|
||||
try {
|
||||
Player player = Bukkit.getPlayer(playerId);
|
||||
//todo improve
|
||||
Set<String> channels = ReflectionUtils.getCastedValue(player, "channels");
|
||||
if (channels != null) {
|
||||
channels.add("floodgate:form");
|
||||
}
|
||||
player.sendPluginMessage(plugin, formChannel, createFormData(form));
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,3 @@ author: ${project.organization.name}
|
||||
website: ${project.url}
|
||||
main: org.geysermc.floodgate.SpigotPlugin
|
||||
api-version: 1.13
|
||||
commands: #todo maybe add the commands directly to the commandmap?
|
||||
linkaccount:
|
||||
unlinkaccount:
|
||||
@@ -25,12 +25,14 @@
|
||||
|
||||
package org.geysermc.floodgate.command;
|
||||
|
||||
import static org.geysermc.floodgate.command.CommonCommandMessage.NOT_A_PLAYER;
|
||||
|
||||
import com.velocitypowered.api.command.CommandManager;
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.command.RawCommand;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import java.util.Locale;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.floodgate.platform.command.Command;
|
||||
import org.geysermc.floodgate.platform.command.CommandRegistration;
|
||||
import org.geysermc.floodgate.platform.command.CommandUtil;
|
||||
@@ -48,26 +50,26 @@ public final class VelocityCommandRegistration implements CommandRegistration {
|
||||
|
||||
commandManager.register(command.getName(),
|
||||
new VelocityCommandWrapper(commandUtil, command, defaultLocale));
|
||||
|
||||
// BrigadierCommand cmd = new BrigadierCommand();
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
protected static final class VelocityCommandWrapper
|
||||
implements com.velocitypowered.api.command.Command {
|
||||
protected static final class VelocityCommandWrapper implements RawCommand {
|
||||
private final CommandUtil commandUtil;
|
||||
private final Command command;
|
||||
private final String defaultLocale;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSource source, @NonNull String[] args) {
|
||||
public void execute(Invocation invocation) {
|
||||
CommandSource source = invocation.source();
|
||||
|
||||
if (!(source instanceof Player)) {
|
||||
if (command.isRequirePlayer()) {
|
||||
commandUtil.sendMessage(
|
||||
source, defaultLocale,
|
||||
CommonCommandMessage.NOT_A_PLAYER
|
||||
);
|
||||
commandUtil.sendMessage(source, defaultLocale, NOT_A_PLAYER);
|
||||
return;
|
||||
}
|
||||
command.execute(source, defaultLocale, args);
|
||||
command.execute(source, defaultLocale, invocation.arguments().split(" "));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,7 +77,10 @@ public final class VelocityCommandRegistration implements CommandRegistration {
|
||||
Locale locale = player.getPlayerSettings().getLocale();
|
||||
String localeString = locale.getLanguage() + "_" + locale.getCountry();
|
||||
|
||||
command.execute(source, player.getUniqueId(), player.getUsername(), localeString, args);
|
||||
command.execute(
|
||||
source, player.getUniqueId(), player.getUsername(),
|
||||
localeString, invocation.arguments().split(" ")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ import io.netty.util.AttributeKey;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
@@ -104,7 +104,7 @@ public final class VelocityListener {
|
||||
|
||||
if (kickMessage != null) {
|
||||
event.setResult(
|
||||
PreLoginEvent.PreLoginComponentResult.denied(TextComponent.of(kickMessage))
|
||||
PreLoginEvent.PreLoginComponentResult.denied(Component.text(kickMessage))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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.listener;
|
||||
|
||||
import static org.geysermc.floodgate.util.MessageFormatter.format;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.name.Named;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||
import com.velocitypowered.api.event.connection.PluginMessageEvent.ForwardResult;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
|
||||
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||
import java.util.UUID;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.geysermc.common.form.Form;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.platform.pluginmessage.PluginMessageHandler;
|
||||
|
||||
//todo naming of this class is different between platforms
|
||||
public class VelocityPluginMessageListener extends PluginMessageHandler {
|
||||
private ProxyServer proxy;
|
||||
private FloodgateLogger logger;
|
||||
private ChannelIdentifier formChannel;
|
||||
|
||||
@Inject // called because this is a listener as well
|
||||
public void init(ProxyServer proxy, FloodgateLogger logger,
|
||||
@Named("formChannel") String formChannelName,
|
||||
@Named("skinChannel") String skinChannelName) {
|
||||
super.proxy = true;
|
||||
this.proxy = proxy;
|
||||
this.logger = logger;
|
||||
|
||||
formChannel = MinecraftChannelIdentifier.from(formChannelName);
|
||||
|
||||
proxy.getChannelRegistrar().register(formChannel);
|
||||
proxy.getChannelRegistrar().register(MinecraftChannelIdentifier.from(skinChannelName));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPluginMessage(PluginMessageEvent event) {
|
||||
ChannelMessageSource source = event.getSource();
|
||||
|
||||
if (event.getIdentifier().equals(formChannel)) {
|
||||
if (source instanceof ServerConnection) {
|
||||
// send it to the client
|
||||
event.setResult(ForwardResult.forward());
|
||||
return;
|
||||
}
|
||||
|
||||
if (source instanceof Player) {
|
||||
byte[] data = event.getData();
|
||||
if (data.length < 2) {
|
||||
logger.error("Invalid form response! Closing connection");
|
||||
((Player) source).disconnect(Component.text("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.setResult(ForwardResult.forward());
|
||||
return;
|
||||
}
|
||||
|
||||
event.setResult(ForwardResult.handled());
|
||||
|
||||
if (!callResponseConsumer(data)) {
|
||||
logger.error(format(
|
||||
"Couldn't find stored form with id {} for player {}",
|
||||
formId, ((Player) source).getUsername()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// proxies don't have to receive anything from the skins channel, they only have to send
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendForm(UUID uuid, Form form) {
|
||||
return proxy.getPlayer(uuid)
|
||||
.map(value -> value.sendPluginMessage(formChannel, createFormData(form)))
|
||||
.orElse(false);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import com.google.inject.Singleton;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.multibindings.ProvidesIntoSet;
|
||||
import org.geysermc.floodgate.listener.VelocityListener;
|
||||
import org.geysermc.floodgate.platform.pluginmessage.PluginMessageHandler;
|
||||
import org.geysermc.floodgate.register.ListenerRegister;
|
||||
|
||||
public final class VelocityListenerModule extends AbstractModule {
|
||||
@@ -43,4 +44,10 @@ public final class VelocityListenerModule extends AbstractModule {
|
||||
public Object velocityListener() {
|
||||
return new VelocityListener();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@ProvidesIntoSet
|
||||
public Object pluginMessageListener(PluginMessageHandler handler) {
|
||||
return handler; // Plugin message handler is also the listener
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,10 +44,12 @@ import org.geysermc.floodgate.crypto.FloodgateCipher;
|
||||
import org.geysermc.floodgate.inject.CommonPlatformInjector;
|
||||
import org.geysermc.floodgate.inject.velocity.VelocityInjector;
|
||||
import org.geysermc.floodgate.listener.VelocityListenerRegistration;
|
||||
import org.geysermc.floodgate.listener.VelocityPluginMessageListener;
|
||||
import org.geysermc.floodgate.logger.Slf4jFloodgateLogger;
|
||||
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.util.LanguageManager;
|
||||
import org.geysermc.floodgate.util.VelocityCommandUtil;
|
||||
import org.slf4j.Logger;
|
||||
@@ -68,8 +70,9 @@ public final class VelocityPlatformModule 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
|
||||
@@ -104,6 +107,12 @@ public final class VelocityPlatformModule extends AbstractModule {
|
||||
return new VelocityListenerRegistration(eventManager, plugin);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public PluginMessageHandler pluginMessageHandler() {
|
||||
return new VelocityPluginMessageListener();
|
||||
}
|
||||
|
||||
/*
|
||||
DebugAddon / PlatformInjector
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ package org.geysermc.floodgate.util;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.platform.command.CommandMessage;
|
||||
import org.geysermc.floodgate.platform.command.CommandUtil;
|
||||
@@ -47,9 +47,9 @@ public final class VelocityCommandUtil implements CommandUtil {
|
||||
cast(player).disconnect(translateAndTransform(locale, message, args));
|
||||
}
|
||||
|
||||
public TextComponent translateAndTransform(String locale, CommandMessage message,
|
||||
public Component translateAndTransform(String locale, CommandMessage message,
|
||||
Object... args) {
|
||||
return TextComponent.of(manager.getString(message.getMessage(), locale, args));
|
||||
return Component.text(manager.getString(message.getMessage(), locale, args));
|
||||
}
|
||||
|
||||
protected Player cast(Object instance) {
|
||||
|
||||
Reference in New Issue
Block a user