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

Moved to Adventure & MiniMessage

This commit is contained in:
Tim203
2024-03-17 12:23:15 +01:00
parent 1c521fba95
commit 3cd5caa416
62 changed files with 608 additions and 401 deletions

View File

@@ -5,6 +5,7 @@ dependencies {
compileOnlyApi(projects.isolation) compileOnlyApi(projects.isolation)
implementation(libs.cloud.bungee) implementation(libs.cloud.bungee)
implementation(libs.adventure.platform.bungee)
} }
relocate("net.kyori") relocate("net.kyori")

View File

@@ -32,11 +32,11 @@ import jakarta.inject.Named;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.addon.data.PacketBlocker; import org.geysermc.floodgate.core.addon.data.PacketBlocker;
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig; import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.core.connection.DataSeeker; import org.geysermc.floodgate.core.connection.DataSeeker;
import org.geysermc.floodgate.core.connection.FloodgateDataHandler; import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
@Singleton @Singleton
public class BungeeDataAddon implements InjectorAddon { public class BungeeDataAddon implements InjectorAddon {

View File

@@ -38,12 +38,12 @@ import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.PacketWrapper; import net.md_5.bungee.protocol.PacketWrapper;
import net.md_5.bungee.protocol.packet.Handshake; import net.md_5.bungee.protocol.packet.Handshake;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.addon.data.CommonNettyDataHandler; import org.geysermc.floodgate.core.addon.data.CommonNettyDataHandler;
import org.geysermc.floodgate.core.addon.data.PacketBlocker; import org.geysermc.floodgate.core.addon.data.PacketBlocker;
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig; import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.core.connection.DataSeeker; import org.geysermc.floodgate.core.connection.DataSeeker;
import org.geysermc.floodgate.core.connection.FloodgateDataHandler; import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.util.ReflectionUtils; import org.geysermc.floodgate.core.util.ReflectionUtils;
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")

View File

@@ -39,9 +39,9 @@ import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.MinecraftEncoder; import net.md_5.bungee.protocol.MinecraftEncoder;
import net.md_5.bungee.protocol.Varint21LengthFieldExtraBufPrepender; import net.md_5.bungee.protocol.Varint21LengthFieldExtraBufPrepender;
import net.md_5.bungee.protocol.Varint21LengthFieldPrepender; import net.md_5.bungee.protocol.Varint21LengthFieldPrepender;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.bungee.util.BungeeReflectionUtils; import org.geysermc.floodgate.bungee.util.BungeeReflectionUtils;
import org.geysermc.floodgate.core.inject.CommonPlatformInjector; import org.geysermc.floodgate.core.inject.CommonPlatformInjector;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.util.ReflectionUtils; import org.geysermc.floodgate.core.util.ReflectionUtils;
@Singleton @Singleton

View File

@@ -42,11 +42,11 @@ import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority; import net.md_5.bungee.event.EventPriority;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.bungee.player.BungeeConnectionManager; import org.geysermc.floodgate.bungee.player.BungeeConnectionManager;
import org.geysermc.floodgate.core.api.SimpleFloodgateApi; import org.geysermc.floodgate.core.api.SimpleFloodgateApi;
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig; import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.core.listener.McListener; import org.geysermc.floodgate.core.listener.McListener;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.skin.SkinApplier; import org.geysermc.floodgate.core.skin.SkinApplier;
import org.geysermc.floodgate.core.skin.SkinDataImpl; import org.geysermc.floodgate.core.skin.SkinDataImpl;
import org.geysermc.floodgate.core.util.LanguageManager; import org.geysermc.floodgate.core.util.LanguageManager;

View File

@@ -38,8 +38,8 @@ import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority; import net.md_5.bungee.event.EventPriority;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.listener.McListener; import org.geysermc.floodgate.core.listener.McListener;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils; import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils;
import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel; import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel;
import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel.Identity; import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel.Identity;

View File

@@ -42,9 +42,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent; import org.geysermc.floodgate.api.event.skin.SkinApplyEvent;
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.event.EventBus; import org.geysermc.floodgate.core.event.EventBus;
import org.geysermc.floodgate.core.event.skin.SkinApplyEventImpl; import org.geysermc.floodgate.core.event.skin.SkinApplyEventImpl;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.skin.SkinApplier; import org.geysermc.floodgate.core.skin.SkinApplier;
import org.geysermc.floodgate.core.skin.SkinDataImpl; import org.geysermc.floodgate.core.skin.SkinDataImpl;
import org.geysermc.floodgate.core.util.ReflectionUtils; import org.geysermc.floodgate.core.util.ReflectionUtils;

View File

@@ -29,6 +29,8 @@ import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import java.util.Collection; import java.util.Collection;
import java.util.UUID; import java.util.UUID;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
@@ -38,6 +40,7 @@ import org.geysermc.floodgate.core.connection.audience.UserAudience;
import org.geysermc.floodgate.core.connection.audience.UserAudience.ConsoleAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience.ConsoleAudience;
import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience;
import org.geysermc.floodgate.core.platform.command.CommandUtil; import org.geysermc.floodgate.core.platform.command.CommandUtil;
import org.geysermc.floodgate.core.util.Constants;
import org.geysermc.floodgate.core.util.LanguageManager; import org.geysermc.floodgate.core.util.LanguageManager;
import org.geysermc.floodgate.core.util.Utils; import org.geysermc.floodgate.core.util.Utils;
@@ -106,15 +109,25 @@ public final class BungeeCommandUtil extends CommandUtil {
} }
@Override @Override
public void sendMessage(Object target, String message) { public void sendMessage(Object target, Component message) {
((CommandSender) target).sendMessage(message); if (target instanceof ProxiedPlayer player && player.getPendingConnection().getVersion() >= Constants.PROTOCOL_HEX_COLOR) {
player.sendMessage(BungeeComponentSerializer.get().serialize(message));
return;
}
((CommandSender) target).sendMessage(BungeeComponentSerializer.legacy().serialize(message));
} }
@Override @Override
public void kickPlayer(Object player, String message) { public void kickPlayer(Object target, Component message) {
// can also be a console // can also be a console
if (player instanceof ProxiedPlayer) { if (!(target instanceof ProxiedPlayer player)) {
((ProxiedPlayer) player).disconnect(message); return;
} }
if (player.getPendingConnection().getVersion() >= Constants.PROTOCOL_HEX_COLOR) {
player.disconnect(BungeeComponentSerializer.get().serialize(message));
return;
}
player.disconnect(BungeeComponentSerializer.legacy().serialize(message));
} }
} }

View File

@@ -25,8 +25,6 @@
package org.geysermc.floodgate.bungee.util; package org.geysermc.floodgate.bungee.util;
import static org.geysermc.floodgate.core.util.MessageFormatter.format;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@@ -40,12 +38,13 @@ public class BungeeReflectionUtils {
unsafeField.setAccessible(true); unsafeField.setAccessible(true);
UNSAFE = (sun.misc.Unsafe) unsafeField.get(null); UNSAFE = (sun.misc.Unsafe) unsafeField.get(null);
} catch (Exception exception) { } catch (Exception exception) {
throw new RuntimeException(format( throw new RuntimeException(
"Cannot initialize required reflection setup :/\nJava version: {}\nVendor: {} ({})", String.format(
"Cannot initialize required reflection setup :/\nJava version: %s\nVendor: %s (%s)",
System.getProperty("java.version"), System.getProperty("java.version"),
System.getProperty("java.vendor"), System.getProperty("java.vendor"),
System.getProperty("java.vendor.url") System.getProperty("java.vendor.url")),
), exception); exception);
} }
} }
@@ -62,12 +61,14 @@ public class BungeeReflectionUtils {
} else { } else {
UNSAFE.putObject(object, offset, result); UNSAFE.putObject(object, offset, result);
} }
} catch (Exception e) { } catch (Exception exception) {
throw new RuntimeException(format( throw new RuntimeException(
"Java version: {}\nVendor: {} ({})", String.format(
"Java version: %s\nVendor: %s (%s)",
System.getProperty("java.version"), System.getProperty("java.version"),
System.getProperty("java.vendor"), System.getProperty("java.vendor"),
System.getProperty("java.vendor.url"), e)); System.getProperty("java.vendor.url")),
exception);
} }
} }
} }

View File

@@ -21,6 +21,7 @@ dependencies {
api(libs.cloud.core) api(libs.cloud.core)
api(libs.snakeyaml) api(libs.snakeyaml)
api(libs.bstats) api(libs.bstats)
api(libs.adventure.text.minimessage)
api(libs.micronaut.inject) api(libs.micronaut.inject)
annotationProcessor(libs.micronaut.inject.java) annotationProcessor(libs.micronaut.inject.java)

View File

@@ -39,7 +39,6 @@ import org.geysermc.floodgate.api.InstanceHolder;
import org.geysermc.floodgate.api.event.FloodgateEventBus; import org.geysermc.floodgate.api.event.FloodgateEventBus;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers; import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.api.inject.PlatformInjector; import org.geysermc.floodgate.api.inject.PlatformInjector;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.packet.PacketHandlers; import org.geysermc.floodgate.api.packet.PacketHandlers;
import org.geysermc.floodgate.core.config.ConfigLoader; import org.geysermc.floodgate.core.config.ConfigLoader;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
@@ -47,6 +46,9 @@ import org.geysermc.floodgate.core.database.loader.DatabaseLoader;
import org.geysermc.floodgate.core.event.EventBus; import org.geysermc.floodgate.core.event.EventBus;
import org.geysermc.floodgate.core.event.lifecycle.PostEnableEvent; import org.geysermc.floodgate.core.event.lifecycle.PostEnableEvent;
import org.geysermc.floodgate.core.event.lifecycle.ShutdownEvent; import org.geysermc.floodgate.core.event.lifecycle.ShutdownEvent;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.CommonPlatformMessages;
import org.geysermc.floodgate.core.platform.command.Placeholder;
import org.geysermc.floodgate.isolation.IsolatedPlatform; import org.geysermc.floodgate.isolation.IsolatedPlatform;
import org.geysermc.floodgate.isolation.library.LibraryManager; import org.geysermc.floodgate.isolation.library.LibraryManager;
@@ -98,8 +100,9 @@ public abstract class FloodgatePlatform implements IsolatedPlatform {
Geyser.set(api); Geyser.set(api);
long endTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis();
context.getBean(FloodgateLogger.class) context.getBean(FloodgateLogger.class).translatedInfo(
.translatedInfo("floodgate.core.finish", endTime - startTime); CommonPlatformMessages.CORE_FINISH,
Placeholder.literal("time_in_ms", endTime - startTime));
} }
@Override @Override

View File

@@ -31,11 +31,11 @@ import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.addon.debug.ChannelInDebugHandler; import org.geysermc.floodgate.core.addon.debug.ChannelInDebugHandler;
import org.geysermc.floodgate.core.addon.debug.ChannelOutDebugHandler; import org.geysermc.floodgate.core.addon.debug.ChannelOutDebugHandler;
import org.geysermc.floodgate.core.addon.debug.StateChangeDetector; import org.geysermc.floodgate.core.addon.debug.StateChangeDetector;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.util.Utils; import org.geysermc.floodgate.core.util.Utils;
@Singleton @Singleton

View File

@@ -35,13 +35,13 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.connection.DataSeeker; import org.geysermc.floodgate.core.connection.DataSeeker;
import org.geysermc.floodgate.core.connection.DataSeeker.DataSeekerResult; import org.geysermc.floodgate.core.connection.DataSeeker.DataSeekerResult;
import org.geysermc.floodgate.core.connection.FloodgateDataHandler; import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
import org.geysermc.floodgate.core.connection.FloodgateDataHandler.HandleResult; import org.geysermc.floodgate.core.connection.FloodgateDataHandler.HandleResult;
import org.geysermc.floodgate.core.crypto.exception.UnsupportedVersionException; import org.geysermc.floodgate.core.crypto.exception.UnsupportedVersionException;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.util.InvalidFormatException; import org.geysermc.floodgate.core.util.InvalidFormatException;
@RequiredArgsConstructor @RequiredArgsConstructor

View File

@@ -30,7 +30,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.core.logger.FloodgateLogger;
@Sharable @Sharable
public final class ChannelInDebugHandler extends SimpleChannelInboundHandler<ByteBuf> { public final class ChannelInDebugHandler extends SimpleChannelInboundHandler<ByteBuf> {

View File

@@ -30,7 +30,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToByteEncoder;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.core.logger.FloodgateLogger;
@Sharable @Sharable
public final class ChannelOutDebugHandler extends MessageToByteEncoder<ByteBuf> { public final class ChannelOutDebugHandler extends MessageToByteEncoder<ByteBuf> {

View File

@@ -30,7 +30,7 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.Constants;
import org.geysermc.floodgate.core.util.Utils; import org.geysermc.floodgate.core.util.Utils;

View File

@@ -39,10 +39,10 @@ import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.cumulus.form.util.FormBuilder;
import org.geysermc.floodgate.api.InstanceHolder; import org.geysermc.floodgate.api.InstanceHolder;
import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.connection.ConnectionManager; import org.geysermc.floodgate.core.connection.ConnectionManager;
import org.geysermc.floodgate.core.http.xbox.XboxClient; import org.geysermc.floodgate.core.http.xbox.XboxClient;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.pluginmessage.PluginMessageManager; import org.geysermc.floodgate.core.pluginmessage.PluginMessageManager;
import org.geysermc.floodgate.core.pluginmessage.channel.FormChannel; import org.geysermc.floodgate.core.pluginmessage.channel.FormChannel;
import org.geysermc.floodgate.core.pluginmessage.channel.TransferChannel; import org.geysermc.floodgate.core.pluginmessage.channel.TransferChannel;

View File

@@ -25,32 +25,19 @@
package org.geysermc.floodgate.core.command; package org.geysermc.floodgate.core.command;
import lombok.Getter; import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage; import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
/** /**
* Messages (or part of messages) that are used in two or more commands and thus are 'commonly * Messages (or part of messages) that are used in two or more commands and thus are 'commonly
* used' * used'
*/ */
@Getter public class CommonCommandMessage {
public enum CommonCommandMessage implements TranslatableMessage { public static final TranslatableMessage LINKING_DISABLED = new TranslatableMessage("floodgate.commands.linking_disabled", MessageType.ERROR);
LINKING_DISABLED("floodgate.commands.linking_disabled"), public static final TranslatableMessage NOT_A_PLAYER = new TranslatableMessage("floodgate.commands.not_a_player", MessageType.ERROR);
NOT_A_PLAYER("floodgate.commands.not_a_player"), public static final TranslatableMessage CHECK_CONSOLE = new TranslatableMessage("floodgate.commands.check_console");
CHECK_CONSOLE("floodgate.commands.check_console"), public static final TranslatableMessage UNEXPECTED_ERROR = new TranslatableMessage("floodgate.commands.unexpected_error " + CommonCommandMessage.CHECK_CONSOLE, MessageType.ERROR);
IS_LINKED_ERROR("floodgate.commands.is_linked_error"), public static final TranslatableMessage IS_LINKED_ERROR = new TranslatableMessage("floodgate.commands.is_linked_error", MessageType.ERROR);
LOCAL_LINKING_NOTICE("floodgate.commands.local_linking_notice"), public static final TranslatableMessage LOCAL_LINKING_NOTICE = new TranslatableMessage("floodgate.commands.local_linking_notice", MessageType.INFO);
GLOBAL_LINKING_NOTICE("floodgate.commands.global_linking_notice"); public static final TranslatableMessage GLOBAL_LINKING_NOTICE = new TranslatableMessage("floodgate.commands.global_linking_notice", MessageType.INFO);
private final String rawMessage;
private final String[] translateParts;
CommonCommandMessage(String rawMessage) {
this.rawMessage = rawMessage;
this.translateParts = rawMessage.split(" ");
}
@Override
public String toString() {
return getRawMessage();
}
} }

View File

@@ -25,13 +25,12 @@
package org.geysermc.floodgate.core.command; package org.geysermc.floodgate.core.command;
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import static org.incendo.cloud.parser.standard.StringParser.stringParser; import static org.incendo.cloud.parser.standard.StringParser.stringParser;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import lombok.Getter;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.api.SimpleFloodgateApi; import org.geysermc.floodgate.core.api.SimpleFloodgateApi;
import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.command.util.Permission;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
@@ -40,7 +39,9 @@ import org.geysermc.floodgate.core.connection.audience.UserAudience;
import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience;
import org.geysermc.floodgate.core.link.CommonPlayerLink; import org.geysermc.floodgate.core.link.CommonPlayerLink;
import org.geysermc.floodgate.core.link.LinkVerificationException; import org.geysermc.floodgate.core.link.LinkVerificationException;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.command.FloodgateCommand; import org.geysermc.floodgate.core.platform.command.FloodgateCommand;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage; import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.Constants;
import org.geysermc.floodgate.core.util.Utils; import org.geysermc.floodgate.core.util.Utils;
@@ -75,11 +76,15 @@ public final class LinkAccountCommand implements FloodgateCommand {
if (!linkState.globalLinkingEnabled()) { if (!linkState.globalLinkingEnabled()) {
sender.sendMessage(CommonCommandMessage.LINKING_DISABLED); sender.sendMessage(CommonCommandMessage.LINKING_DISABLED);
} else { } else {
sender.sendMessage(CommonCommandMessage.GLOBAL_LINKING_NOTICE, Constants.LINK_INFO_URL); sender.sendMessage(
CommonCommandMessage.GLOBAL_LINKING_NOTICE,
literal("url", Constants.LINK_INFO_URL));
} }
return; return;
} else if (linkState.globalLinkingEnabled()) { } else if (linkState.globalLinkingEnabled()) {
sender.sendMessage(CommonCommandMessage.LOCAL_LINKING_NOTICE, Constants.LINK_INFO_URL); sender.sendMessage(
CommonCommandMessage.LOCAL_LINKING_NOTICE,
literal("url", Constants.LINK_INFO_URL));
} }
ProfileAudience targetUser = context.get("player"); ProfileAudience targetUser = context.get("player");
@@ -89,7 +94,7 @@ public final class LinkAccountCommand implements FloodgateCommand {
// when the player is a Bedrock player // when the player is a Bedrock player
if (api.isBedrockPlayer(sender.uuid())) { if (api.isBedrockPlayer(sender.uuid())) {
if (!context.contains("code")) { if (!context.contains("code")) {
sender.sendMessage(Message.BEDROCK_USAGE); sender.sendMessage(Message.BEDROCK_USAGE, literal("command", "/linkaccount <gamertag>"));
return; return;
} }
@@ -121,20 +126,23 @@ public final class LinkAccountCommand implements FloodgateCommand {
) )
.whenComplete(($, throwable) -> { .whenComplete(($, throwable) -> {
if (throwable instanceof LinkVerificationException exception) { if (throwable instanceof LinkVerificationException exception) {
sender.sendMessage(exception.message()); sender.sendMessage(exception.message(), exception.placeholders());
return; return;
} }
if (throwable != null) { if (throwable != null) {
sender.sendMessage(Message.LINK_REQUEST_ERROR); sender.sendMessage(Message.LINK_REQUEST_ERROR);
return; return;
} }
sender.disconnect(Message.LINK_REQUEST_COMPLETED, targetName); sender.disconnect(
Message.LINK_REQUEST_COMPLETED,
literal("target", targetName),
literal("command", "/unlinkaccount"));
}); });
return; return;
} }
if (context.contains("code")) { if (context.contains("code")) {
sender.sendMessage(Message.JAVA_USAGE); sender.sendMessage(Message.JAVA_USAGE, literal("command", "/linkaccount <gamertag>"));
return; return;
} }
@@ -147,7 +155,11 @@ public final class LinkAccountCommand implements FloodgateCommand {
sender.sendMessage(Message.LINK_REQUEST_ERROR); sender.sendMessage(Message.LINK_REQUEST_ERROR);
return; return;
} }
sender.sendMessage(Message.LINK_REQUEST_CREATED, targetName, username, code); sender.sendMessage(
Message.LINK_REQUEST_CREATED,
literal("target", targetName),
literal("command", "/linkaccount " + username + " " + code),
literal("unlink_command", "/unlinkaccount"));
}); });
} }
@@ -158,24 +170,15 @@ public final class LinkAccountCommand implements FloodgateCommand {
(linkConfig.enableOwnLinking() || linkConfig.enableGlobalLinking()); (linkConfig.enableOwnLinking() || linkConfig.enableGlobalLinking());
} }
@Getter public static final class Message {
public enum Message implements TranslatableMessage { public static final TranslatableMessage ALREADY_LINKED = new TranslatableMessage("floodgate.command.link_account.already_linked", MessageType.ERROR);
ALREADY_LINKED("floodgate.command.link_account.already_linked"), public static final TranslatableMessage JAVA_USAGE = new TranslatableMessage("floodgate.command.link_account.java_usage", MessageType.ERROR);
JAVA_USAGE("floodgate.command.link_account.java_usage"), public static final TranslatableMessage LINK_REQUEST_CREATED = new TranslatableMessage("floodgate.command.link_account.link_request_created", MessageType.SUCCESS);
LINK_REQUEST_CREATED("floodgate.command.link_account.link_request_created"), public static final TranslatableMessage BEDROCK_USAGE = new TranslatableMessage("floodgate.command.link_account.bedrock_usage", MessageType.ERROR);
BEDROCK_USAGE("floodgate.command.link_account.bedrock_usage"), public static final TranslatableMessage LINK_REQUEST_EXPIRED = new TranslatableMessage("floodgate.command.link_account.link_request_expired", MessageType.ERROR);
LINK_REQUEST_EXPIRED("floodgate.command.link_account.link_request_expired"), public static final TranslatableMessage LINK_REQUEST_COMPLETED = new TranslatableMessage("floodgate.command.link_account.link_request_completed", MessageType.SUCCESS);
LINK_REQUEST_COMPLETED("floodgate.command.link_account.link_request_completed"), public static final TranslatableMessage LINK_REQUEST_ERROR = new TranslatableMessage("floodgate.command.link_account.link_request_error " + CommonCommandMessage.CHECK_CONSOLE, MessageType.ERROR);
LINK_REQUEST_ERROR("floodgate.command.link_request.error " + CommonCommandMessage.CHECK_CONSOLE), public static final TranslatableMessage INVALID_CODE = new TranslatableMessage("floodgate.command.link_account.invalid_code", MessageType.ERROR);
INVALID_CODE("floodgate.command.link_account.invalid_code"), public static final TranslatableMessage NO_LINK_REQUESTED = new TranslatableMessage("floodgate.command.link_account.no_link_requested", MessageType.ERROR);
NO_LINK_REQUESTED("floodgate.command.link_account.no_link_requested");
private final String rawMessage;
private final String[] translateParts;
Message(String rawMessage) {
this.rawMessage = rawMessage;
this.translateParts = rawMessage.split(" ");
}
} }
} }

View File

@@ -25,15 +25,17 @@
package org.geysermc.floodgate.core.command; package org.geysermc.floodgate.core.command;
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import lombok.Getter;
import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.command.util.Permission;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience;
import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience;
import org.geysermc.floodgate.core.link.CommonPlayerLink; import org.geysermc.floodgate.core.link.CommonPlayerLink;
import org.geysermc.floodgate.core.platform.command.FloodgateCommand; import org.geysermc.floodgate.core.platform.command.FloodgateCommand;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage; import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.Constants;
import org.incendo.cloud.Command; import org.incendo.cloud.Command;
@@ -63,11 +65,13 @@ public final class UnlinkAccountCommand implements FloodgateCommand {
if (!linkState.globalLinkingEnabled()) { if (!linkState.globalLinkingEnabled()) {
sender.sendMessage(CommonCommandMessage.LINKING_DISABLED); sender.sendMessage(CommonCommandMessage.LINKING_DISABLED);
} else { } else {
sender.sendMessage(CommonCommandMessage.GLOBAL_LINKING_NOTICE, Constants.LINK_INFO_URL); sender.sendMessage(
CommonCommandMessage.GLOBAL_LINKING_NOTICE,
literal("url", Constants.LINK_INFO_URL));
} }
return; return;
} else if (linkState.globalLinkingEnabled()) { } else if (linkState.globalLinkingEnabled()) {
sender.sendMessage(CommonCommandMessage.LOCAL_LINKING_NOTICE, Constants.LINK_INFO_URL); sender.sendMessage(CommonCommandMessage.LOCAL_LINKING_NOTICE, literal("url", Constants.LINK_INFO_URL));
} }
link.isLinked(sender.uuid()) link.isLinked(sender.uuid())
@@ -101,18 +105,9 @@ public final class UnlinkAccountCommand implements FloodgateCommand {
(linkConfig.enableOwnLinking() || linkConfig.enableGlobalLinking()); (linkConfig.enableOwnLinking() || linkConfig.enableGlobalLinking());
} }
@Getter public static final class Message {
public enum Message implements TranslatableMessage { public static final TranslatableMessage NOT_LINKED = new TranslatableMessage("floodgate.command.unlink_account.not_linked", MessageType.ERROR);
NOT_LINKED("floodgate.command.unlink_account.not_linked"), public static final TranslatableMessage UNLINK_SUCCESS = new TranslatableMessage("floodgate.command.unlink_account.unlink_success", MessageType.SUCCESS);
UNLINK_SUCCESS("floodgate.command.unlink_account.unlink_success"), public static final TranslatableMessage UNLINK_ERROR = new TranslatableMessage("floodgate.command.unlink_account.error " + CommonCommandMessage.CHECK_CONSOLE, MessageType.ERROR);
UNLINK_ERROR("floodgate.command.unlink_account.error " + CommonCommandMessage.CHECK_CONSOLE);
private final String rawMessage;
private final String[] translateParts;
Message(String rawMessage) {
this.rawMessage = rawMessage;
this.translateParts = rawMessage.split(" ");
}
} }
} }

View File

@@ -25,20 +25,22 @@
package org.geysermc.floodgate.core.command; package org.geysermc.floodgate.core.command;
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import io.micronaut.http.client.exceptions.HttpClientResponseException; import io.micronaut.http.client.exceptions.HttpClientResponseException;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import java.util.UUID; import java.util.UUID;
import lombok.Getter;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.command.util.Permission;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig; import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.core.connection.audience.ProfileAudience; import org.geysermc.floodgate.core.connection.audience.ProfileAudience;
import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience;
import org.geysermc.floodgate.core.http.xbox.XboxClient; import org.geysermc.floodgate.core.http.xbox.XboxClient;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.command.CommandUtil; import org.geysermc.floodgate.core.platform.command.CommandUtil;
import org.geysermc.floodgate.core.platform.command.FloodgateCommand; import org.geysermc.floodgate.core.platform.command.FloodgateCommand;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage; import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
import org.incendo.cloud.Command; import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager; import org.incendo.cloud.CommandManager;
@@ -76,7 +78,7 @@ public class WhitelistCommand implements FloodgateCommand {
String name = profile.username(); String name = profile.username();
if (name == null && uuid == null) { if (name == null && uuid == null) {
sender.sendMessage(Message.UNEXPECTED_ERROR); sender.sendMessage(CommonCommandMessage.UNEXPECTED_ERROR);
return; return;
} }
@@ -90,16 +92,15 @@ public class WhitelistCommand implements FloodgateCommand {
if (add) { if (add) {
if (commandUtil.whitelistPlayer(uuid, "unknown")) { if (commandUtil.whitelistPlayer(uuid, "unknown")) {
sender.sendMessage(Message.PLAYER_ADDED, uuid.toString()); sender.sendMessage(Message.PLAYER_ADDED, literal("target", uuid.toString()));
} else { } else {
sender.sendMessage(Message.PLAYER_ALREADY_WHITELISTED, sender.sendMessage(Message.PLAYER_ALREADY_WHITELISTED, literal("target", uuid.toString()));
uuid.toString());
} }
} else { } else {
if (commandUtil.removePlayerFromWhitelist(uuid, "unknown")) { if (commandUtil.removePlayerFromWhitelist(uuid, "unknown")) {
sender.sendMessage(Message.PLAYER_REMOVED, uuid.toString()); sender.sendMessage(Message.PLAYER_REMOVED, literal("target", uuid.toString()));
} else { } else {
sender.sendMessage(Message.PLAYER_NOT_WHITELISTED, uuid.toString()); sender.sendMessage(Message.PLAYER_NOT_WHITELISTED, literal("target", uuid.toString()));
} }
} }
return; return;
@@ -132,7 +133,7 @@ public class WhitelistCommand implements FloodgateCommand {
error.printStackTrace(); error.printStackTrace();
return; return;
} }
sender.sendMessage(Message.UNEXPECTED_ERROR); sender.sendMessage(CommonCommandMessage.UNEXPECTED_ERROR);
//todo proper non-200 status handler //todo proper non-200 status handler
// var response = exception.getResponse().getBody(UnsuccessfulResponse.class); // var response = exception.getResponse().getBody(UnsuccessfulResponse.class);
@@ -149,7 +150,7 @@ public class WhitelistCommand implements FloodgateCommand {
Long xuid = result.xuid(); Long xuid = result.xuid();
if (xuid == null) { if (xuid == null) {
sender.sendMessage(Message.USER_NOT_FOUND); sender.sendMessage(Message.ACCOUNT_NOT_FOUND);
return; return;
} }
@@ -158,16 +159,15 @@ public class WhitelistCommand implements FloodgateCommand {
try { try {
if (add) { if (add) {
if (commandUtil.whitelistPlayer(xuid, correctName)) { if (commandUtil.whitelistPlayer(xuid, correctName)) {
sender.sendMessage(Message.PLAYER_ADDED, strippedName); sender.sendMessage(Message.PLAYER_ADDED, literal("target", strippedName));
} else { } else {
sender.sendMessage(Message.PLAYER_ALREADY_WHITELISTED, sender.sendMessage(Message.PLAYER_ALREADY_WHITELISTED, literal("target", strippedName));
strippedName);
} }
} else { } else {
if (commandUtil.removePlayerFromWhitelist(xuid, correctName)) { if (commandUtil.removePlayerFromWhitelist(xuid, correctName)) {
sender.sendMessage(Message.PLAYER_REMOVED, strippedName); sender.sendMessage(Message.PLAYER_REMOVED, literal("target", strippedName));
} else { } else {
sender.sendMessage(Message.PLAYER_NOT_WHITELISTED, strippedName); sender.sendMessage(Message.PLAYER_NOT_WHITELISTED, literal("target", strippedName));
} }
} }
} catch (Exception exception) { } catch (Exception exception) {
@@ -185,23 +185,13 @@ public class WhitelistCommand implements FloodgateCommand {
return !(config instanceof ProxyFloodgateConfig); return !(config instanceof ProxyFloodgateConfig);
} }
@Getter public static final class Message {
public enum Message implements TranslatableMessage { public static final TranslatableMessage INVALID_USERNAME = new TranslatableMessage("floodgate.command.fwhitelist.invalid_username", MessageType.ERROR);
INVALID_USERNAME("floodgate.command.fwhitelist.invalid_username"), public static final TranslatableMessage API_UNAVAILABLE = new TranslatableMessage("floodgate.command.fwhitelist.api_unavailable " + CommonCommandMessage.CHECK_CONSOLE, MessageType.ERROR);
API_UNAVAILABLE("floodgate.command.fwhitelist.api_unavailable " + CommonCommandMessage.CHECK_CONSOLE), public static final TranslatableMessage ACCOUNT_NOT_FOUND = new TranslatableMessage("floodgate.command.fwhitelist.account_not_found", MessageType.ERROR);
USER_NOT_FOUND("floodgate.command.fwhitelist.user_not_found"), public static final TranslatableMessage PLAYER_ADDED = new TranslatableMessage("floodgate.command.fwhitelist.player_added", MessageType.SUCCESS);
PLAYER_ADDED("floodgate.command.fwhitelist.player_added"), public static final TranslatableMessage PLAYER_REMOVED = new TranslatableMessage("floodgate.command.fwhitelist.player_removed", MessageType.SUCCESS);
PLAYER_REMOVED("floodgate.command.fwhitelist.player_removed"), public static final TranslatableMessage PLAYER_ALREADY_WHITELISTED = new TranslatableMessage("floodgate.command.fwhitelist.player_already_whitelisted", MessageType.NORMAL);
PLAYER_ALREADY_WHITELISTED("floodgate.command.fwhitelist.player_already_whitelisted"), public static final TranslatableMessage PLAYER_NOT_WHITELISTED = new TranslatableMessage("floodgate.command.fwhitelist.player_not_whitelisted", MessageType.NORMAL);
PLAYER_NOT_WHITELISTED("floodgate.command.fwhitelist.player_not_whitelisted"),
UNEXPECTED_ERROR("floodgate.command.fwhitelist.unexpected_error " + CommonCommandMessage.CHECK_CONSOLE);
private final String rawMessage;
private final String[] translateParts;
Message(String rawMessage) {
this.rawMessage = rawMessage;
this.translateParts = rawMessage.split(" ");
}
} }
} }

View File

@@ -1,6 +1,7 @@
package org.geysermc.floodgate.core.command.linkedaccounts; package org.geysermc.floodgate.core.command.linkedaccounts;
import static org.geysermc.floodgate.core.command.linkedaccounts.LinkedAccountsCommand.linkInfoMessage; import static org.geysermc.floodgate.core.platform.command.Placeholder.dynamic;
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
@@ -8,15 +9,18 @@ import java.util.ArrayList;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.command.CommonCommandMessage; import org.geysermc.floodgate.core.command.CommonCommandMessage;
import org.geysermc.floodgate.core.command.LinkAccountCommand; import org.geysermc.floodgate.core.command.LinkAccountCommand;
import org.geysermc.floodgate.core.command.linkedaccounts.LinkedAccountsCommand.LinkedAccountsCommonMessage;
import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.command.util.Permission;
import org.geysermc.floodgate.core.connection.audience.ProfileAudience; import org.geysermc.floodgate.core.connection.audience.ProfileAudience;
import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience;
import org.geysermc.floodgate.core.http.ProfileFetcher; import org.geysermc.floodgate.core.http.ProfileFetcher;
import org.geysermc.floodgate.core.link.LocalPlayerLinking; import org.geysermc.floodgate.core.link.LocalPlayerLinking;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.Constants;
import org.incendo.cloud.Command; import org.incendo.cloud.Command;
import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandContext;
@@ -49,7 +53,7 @@ final class AddLinkedAccountCommand extends FloodgateSubCommand {
var linking = optionalLinking.get(); var linking = optionalLinking.get();
if (linking.state().globalLinkingEnabled()) { if (linking.state().globalLinkingEnabled()) {
sender.sendMessage(CommonCommandMessage.LOCAL_LINKING_NOTICE, Constants.LINK_INFO_URL); sender.sendMessage(CommonCommandMessage.LOCAL_LINKING_NOTICE, literal("url", Constants.LINK_INFO_URL));
} }
ProfileAudience bedrockInput = context.get("bedrock"); ProfileAudience bedrockInput = context.get("bedrock");
@@ -61,7 +65,10 @@ final class AddLinkedAccountCommand extends FloodgateSubCommand {
if (bedrockRef.get().uuid() == null) { if (bedrockRef.get().uuid() == null) {
futures.add(fetcher.fetchXuidFor(bedrockRef.get().username()).thenAccept(bedrockRef::set)); futures.add(fetcher.fetchXuidFor(bedrockRef.get().username()).thenAccept(bedrockRef::set));
} else {
futures.add(fetcher.fetchGamertagFor(bedrockRef.get().uuid()).thenAccept(bedrockRef::set));
} }
if (javaRef.get().uuid() == null) { if (javaRef.get().uuid() == null) {
futures.add(fetcher.fetchUniqueIdFor(javaRef.get().username()).thenAccept(javaRef::set)); futures.add(fetcher.fetchUniqueIdFor(javaRef.get().username()).thenAccept(javaRef::set));
} }
@@ -72,10 +79,16 @@ final class AddLinkedAccountCommand extends FloodgateSubCommand {
var java = javaRef.get(); var java = javaRef.get();
if (bedrock == null) { if (bedrock == null) {
sender.sendMessage("Could not find Bedrock account with username " + bedrockInput.username()); sender.sendMessage(
LinkedAccountsCommonMessage.NOT_FOUND,
literal("platform", "Bedrock"),
literal("target", bedrockInput.username()));
} }
if (java == null) { if (java == null) {
sender.sendMessage("Could not find Java account with username " + javaInput.username()); sender.sendMessage(
LinkedAccountsCommonMessage.NOT_FOUND,
literal("platform", "Java"),
literal("target", javaInput.username()));
} }
linking.addLink(java.uuid(), java.username(), bedrock.uuid()).whenComplete((player, throwable) -> { linking.addLink(java.uuid(), java.username(), bedrock.uuid()).whenComplete((player, throwable) -> {
@@ -84,8 +97,18 @@ final class AddLinkedAccountCommand extends FloodgateSubCommand {
logger.error("Exception while manually linking accounts", throwable); logger.error("Exception while manually linking accounts", throwable);
return; return;
} }
sender.sendMessage("You've successfully linked:\n" + linkInfoMessage(player)); sender.sendMessage(
Message.ADD_SUCCESS,
dynamic("link_info", LinkedAccountsCommonMessage.LINK_INFO, sender),
literal("bedrock_id", bedrock.uuid()),
literal("bedrock_name", bedrock.username()),
literal("java_name", java.username()),
literal("java_uuid", java.uuid()));
}); });
}); });
} }
public static final class Message {
public static final TranslatableMessage ADD_SUCCESS = new TranslatableMessage("floodgate.command.linkedaccounts.add.success", MessageType.SUCCESS);
}
} }

View File

@@ -1,17 +1,23 @@
package org.geysermc.floodgate.core.command.linkedaccounts; package org.geysermc.floodgate.core.command.linkedaccounts;
import static org.geysermc.floodgate.core.platform.command.Placeholder.dynamic;
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.command.CommonCommandMessage; import org.geysermc.floodgate.core.command.CommonCommandMessage;
import org.geysermc.floodgate.core.command.linkedaccounts.LinkedAccountsCommand.LinkedAccountsCommonMessage;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.connection.audience.ProfileAudience; import org.geysermc.floodgate.core.connection.audience.ProfileAudience;
import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience;
import org.geysermc.floodgate.core.http.ProfileFetcher; import org.geysermc.floodgate.core.http.ProfileFetcher;
import org.geysermc.floodgate.core.link.LocalPlayerLinking; import org.geysermc.floodgate.core.link.LocalPlayerLinking;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.Constants;
import org.incendo.cloud.Command; import org.incendo.cloud.Command;
import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandContext;
@@ -43,22 +49,26 @@ final class InfoLinkedAccountCommand extends FloodgateSubCommand {
var linking = optionalLinking.get(); var linking = optionalLinking.get();
if (linking.state().globalLinkingEnabled()) { if (linking.state().globalLinkingEnabled()) {
sender.sendMessage(CommonCommandMessage.LOCAL_LINKING_NOTICE, Constants.LINK_INFO_URL); sender.sendMessage(CommonCommandMessage.LOCAL_LINKING_NOTICE, literal("url", Constants.LINK_INFO_URL));
} }
ProfileAudience playerInput = context.get("player"); ProfileAudience playerInput = context.get("player");
String gamertagInput;
final boolean bedrock; final boolean bedrock;
var future = CompletableFuture.completedFuture(playerInput); var future = CompletableFuture.completedFuture(playerInput);
if (playerInput.uuid() == null) { if (playerInput.uuid() == null) {
if (playerInput.username().startsWith(config.usernamePrefix())) { if (playerInput.username().startsWith(config.usernamePrefix())) {
future = fetcher.fetchXuidFor(playerInput.username().substring(config.usernamePrefix().length())); gamertagInput = playerInput.username().substring(config.usernamePrefix().length());
future = fetcher.fetchXuidFor(gamertagInput);
bedrock = true; bedrock = true;
} else { } else {
gamertagInput = null;
bedrock = false; bedrock = false;
future = fetcher.fetchUniqueIdFor(playerInput.username()); future = fetcher.fetchUniqueIdFor(playerInput.username());
} }
} else { } else {
gamertagInput = null;
bedrock = playerInput.uuid().getMostSignificantBits() == 0; bedrock = playerInput.uuid().getMostSignificantBits() == 0;
} }
@@ -71,13 +81,16 @@ final class InfoLinkedAccountCommand extends FloodgateSubCommand {
} }
if (result == null) { if (result == null) {
sender.sendMessage("Could not find %s user with username %s".formatted(platform, playerInput.username())); sender.sendMessage(
LinkedAccountsCommonMessage.NOT_FOUND,
literal("platform", platform),
literal("target", playerInput.username()));
return; return;
} }
linking.fetchLink(result.uuid()).whenComplete((link, error) -> { linking.fetchLink(result.uuid()).whenComplete((link, error) -> {
if (error != null) { if (error != null) {
sender.sendMessage("Error while looking up player link, see console"); sender.sendMessage(Message.INFO_ERROR);
logger.error("Exception while fetching link status", error); logger.error("Exception while fetching link status", error);
return; return;
} }
@@ -85,13 +98,43 @@ final class InfoLinkedAccountCommand extends FloodgateSubCommand {
var usernameOrUniqueId = playerInput.username() != null ? playerInput.username() : playerInput.uuid(); var usernameOrUniqueId = playerInput.username() != null ? playerInput.username() : playerInput.uuid();
if (link == null) { if (link == null) {
sender.sendMessage("%s user %s is not linked!".formatted(platform, usernameOrUniqueId)); sender.sendMessage(
Message.INFO_NOT_LINKED,
literal("platform", platform),
literal("target", usernameOrUniqueId));
return; return;
} }
sender.sendMessage("Link info for %s user %s:\n%s" CompletableFuture<ProfileAudience> gamertagFetch =
.formatted(platform, usernameOrUniqueId, LinkedAccountsCommand.linkInfoMessage(link))); CompletableFuture.completedFuture(new ProfileAudience(null, gamertagInput));
if (gamertagInput == null) {
gamertagFetch = fetcher.fetchGamertagFor(link.bedrockId());
}
gamertagFetch.whenComplete((gamertagResult, $) -> {
String gamertag = "unknown";
if (gamertagResult != null) {
gamertag = gamertagResult.username();
}
sender.sendMessage(
Message.INFO_LINKED,
literal("platform", platform),
literal("target", usernameOrUniqueId),
dynamic("link_info", LinkedAccountsCommonMessage.LINK_INFO, sender),
literal("bedrock_id", link.bedrockId()),
literal("bedrock_name", gamertag),
literal("java_name", link.javaUsername()),
literal("java_uuid", link.javaUniqueId()));
});
}); });
}); });
} }
public static final class Message {
public static final TranslatableMessage INFO_ERROR = new TranslatableMessage("floodgate.command.linkedaccounts.info.error", MessageType.ERROR);
public static final TranslatableMessage INFO_NOT_LINKED = new TranslatableMessage("floodgate.command.linkedaccounts.info.not_linked", MessageType.NORMAL);
public static final TranslatableMessage INFO_LINKED = new TranslatableMessage("floodgate.command.linkedaccounts.info.linked", MessageType.NORMAL);
}
} }

View File

@@ -2,8 +2,9 @@ package org.geysermc.floodgate.core.command.linkedaccounts;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.command.util.Permission;
import org.geysermc.floodgate.core.database.entity.LinkedPlayer; import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.SubCommands; import org.geysermc.floodgate.core.platform.command.SubCommands;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
@Singleton @Singleton
final class LinkedAccountsCommand extends SubCommands { final class LinkedAccountsCommand extends SubCommands {
@@ -11,9 +12,8 @@ final class LinkedAccountsCommand extends SubCommands {
super("linkedaccounts", "Manage locally linked accounts", Permission.COMMAND_LINKED); super("linkedaccounts", "Manage locally linked accounts", Permission.COMMAND_LINKED);
} }
@Singleton public static final class LinkedAccountsCommonMessage {
static String linkInfoMessage(LinkedPlayer player) { public static final TranslatableMessage NOT_FOUND = new TranslatableMessage("floodgate.command.linkedaccounts.common.not_found", MessageType.ERROR);
return "Java UUID: %s\nJava username: %s\nBedrock UUID: %s" public static final TranslatableMessage LINK_INFO = new TranslatableMessage("floodgate.command.linkedaccounts.common.link_info");
.formatted(player.javaUniqueId(), player.javaUsername(), player.bedrockId());
} }
} }

View File

@@ -1,19 +1,24 @@
package org.geysermc.floodgate.core.command.linkedaccounts; package org.geysermc.floodgate.core.command.linkedaccounts;
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.command.CommonCommandMessage; import org.geysermc.floodgate.core.command.CommonCommandMessage;
import org.geysermc.floodgate.core.command.LinkAccountCommand; import org.geysermc.floodgate.core.command.LinkAccountCommand;
import org.geysermc.floodgate.core.command.linkedaccounts.LinkedAccountsCommand.LinkedAccountsCommonMessage;
import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.command.util.Permission;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.connection.audience.ProfileAudience; import org.geysermc.floodgate.core.connection.audience.ProfileAudience;
import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience;
import org.geysermc.floodgate.core.http.ProfileFetcher; import org.geysermc.floodgate.core.http.ProfileFetcher;
import org.geysermc.floodgate.core.link.LocalPlayerLinking; import org.geysermc.floodgate.core.link.LocalPlayerLinking;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.Constants;
import org.incendo.cloud.Command; import org.incendo.cloud.Command;
import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandContext;
@@ -45,7 +50,7 @@ final class RemoveLinkedAccountCommand extends FloodgateSubCommand {
var linking = optionalLinking.get(); var linking = optionalLinking.get();
if (linking.state().globalLinkingEnabled()) { if (linking.state().globalLinkingEnabled()) {
sender.sendMessage(CommonCommandMessage.LOCAL_LINKING_NOTICE, Constants.LINK_INFO_URL); sender.sendMessage(CommonCommandMessage.LOCAL_LINKING_NOTICE, literal("url", Constants.LINK_INFO_URL));
} }
ProfileAudience playerInput = context.get("player"); ProfileAudience playerInput = context.get("player");
@@ -73,8 +78,10 @@ final class RemoveLinkedAccountCommand extends FloodgateSubCommand {
} }
if (result == null) { if (result == null) {
sender.sendMessage("Could not find %s user with username %s" sender.sendMessage(
.formatted(platform, playerInput.username())); LinkedAccountsCommonMessage.NOT_FOUND,
literal("platform", platform),
literal("target", playerInput.username()));
return; return;
} }
@@ -84,9 +91,15 @@ final class RemoveLinkedAccountCommand extends FloodgateSubCommand {
logger.error("Exception while manually linking accounts", error); logger.error("Exception while manually linking accounts", error);
return; return;
} }
sender.sendMessage("You've successfully unlinked %s user %s" sender.sendMessage(
.formatted(platform, playerInput.username())); Message.REMOVE_SUCCESS,
literal("platform", platform),
literal("target", playerInput.username()));
}); });
}); });
} }
public static final class Message {
public static final TranslatableMessage REMOVE_SUCCESS = new TranslatableMessage("floodgate.command.linkedaccounts.remove.success", MessageType.SUCCESS);
}
} }

View File

@@ -25,7 +25,7 @@
package org.geysermc.floodgate.core.command.main; package org.geysermc.floodgate.core.command.main;
import static org.geysermc.floodgate.core.util.Constants.COLOR_CHAR; import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.Pair;
@@ -37,6 +37,8 @@ import java.util.function.BooleanSupplier;
import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.command.util.Permission;
import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience;
import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.Constants;
import org.geysermc.floodgate.core.util.HttpClient; import org.geysermc.floodgate.core.util.HttpClient;
import org.geysermc.floodgate.core.util.HttpClient.HttpResponse; import org.geysermc.floodgate.core.util.HttpClient.HttpResponse;
@@ -62,10 +64,10 @@ final class FirewallCheckSubcommand extends FloodgateSubCommand {
executeChecks( executeChecks(
globalApiCheck(sender) globalApiCheck(sender)
).whenComplete((response, $) -> ).whenComplete((response, $) ->
sender.sendMessage(String.format( sender.sendMessage(
COLOR_CHAR + "eThe checks have finished. %s/%s were successful", Message.FIREWALL_RESULT,
response.left(), response.left() + response.right() literal("successful", response.left()),
)) literal("total", response.left() + response.right()))
); );
} }
@@ -88,14 +90,14 @@ final class FirewallCheckSubcommand extends FloodgateSubCommand {
private BooleanSupplier executeFirewallText( private BooleanSupplier executeFirewallText(
UserAudience sender, String name, Runnable runnable) { UserAudience sender, String name, Runnable runnable) {
return () -> { return () -> {
sender.sendMessage(COLOR_CHAR + "eTesting " + name + "..."); sender.sendMessage(Message.CHECK_START, literal("target", name));
try { try {
runnable.run(); runnable.run();
sender.sendMessage(COLOR_CHAR + "aWas able to connect to " + name + "!"); sender.sendMessage(Message.CHECK_SUCCESS, literal("target", name));
return true; return true;
} catch (Exception e) { } catch (Exception exception) {
sender.sendMessage(COLOR_CHAR + "cFailed to connect:"); sender.sendMessage(Message.CHECK_FAILED, literal("target", name));
sender.sendMessage(Utils.getStackTrace(e)); sender.sendRaw(Utils.getStackTrace(exception), MessageType.ERROR);
return false; return false;
} }
}; };
@@ -117,4 +119,11 @@ final class FirewallCheckSubcommand extends FloodgateSubCommand {
return Pair.of(okCount.get(), failCount.get()); return Pair.of(okCount.get(), failCount.get());
}); });
} }
public static final class Message {
public static final TranslatableMessage FIREWALL_RESULT = new TranslatableMessage("floodgate.command.main.firewall.result", MessageType.INFO);
public static final TranslatableMessage CHECK_START = new TranslatableMessage("floodgate.command.main.firewall.check.start", MessageType.INFO);
public static final TranslatableMessage CHECK_SUCCESS = new TranslatableMessage("floodgate.command.main.firewall.check.success", MessageType.SUCCESS);
public static final TranslatableMessage CHECK_FAILED = new TranslatableMessage("floodgate.command.main.firewall.check.failed", MessageType.ERROR);
}
} }

View File

@@ -25,16 +25,18 @@
package org.geysermc.floodgate.core.command.main; package org.geysermc.floodgate.core.command.main;
import static org.geysermc.floodgate.core.util.Constants.COLOR_CHAR; import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.core.command.CommonCommandMessage;
import org.geysermc.floodgate.core.command.WhitelistCommand.Message;
import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.command.util.Permission;
import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.Constants;
import org.geysermc.floodgate.core.util.HttpClient; import org.geysermc.floodgate.core.util.HttpClient;
import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandContext;
@@ -56,12 +58,11 @@ public class VersionSubcommand extends FloodgateSubCommand {
@Override @Override
public void execute(CommandContext<UserAudience> context) { public void execute(CommandContext<UserAudience> context) {
UserAudience sender = context.sender(); UserAudience sender = context.sender();
sender.sendMessage(String.format( sender.sendMessage(
COLOR_CHAR + "7You're currently on " + COLOR_CHAR + "b%s" + Message.VERSION_INFO,
COLOR_CHAR + "7 (branch: " + COLOR_CHAR + "b%s" + COLOR_CHAR + "7)\n" + literal("version", Constants.FULL_VERSION),
COLOR_CHAR + "eFetching latest build info...", literal("branch", Constants.GIT_BRANCH));
Constants.FULL_VERSION, Constants.GIT_BRANCH sender.sendMessage(Message.VERSION_FETCH_INFO);
));
String baseUrl = String.format( String baseUrl = String.format(
"https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/%s/lastSuccessfulBuild/", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/%s/lastSuccessfulBuild/",
@@ -73,7 +74,7 @@ public class VersionSubcommand extends FloodgateSubCommand {
JsonElement.class JsonElement.class
).whenComplete((result, error) -> { ).whenComplete((result, error) -> {
if (error != null) { if (error != null) {
sender.sendMessage(COLOR_CHAR + "cCould not retrieve latest version info!"); sender.sendMessage(Message.VERSION_FETCH_ERROR);
error.printStackTrace(); error.printStackTrace();
return; return;
} }
@@ -84,10 +85,7 @@ public class VersionSubcommand extends FloodgateSubCommand {
logger.info("{}", result.getHttpCode()); logger.info("{}", result.getHttpCode());
if (result.getHttpCode() == 404) { if (result.getHttpCode() == 404) {
sender.sendMessage( sender.sendMessage(Message.VERSION_FETCH_NOT_FOUND);
COLOR_CHAR + "cGot a 404 (not found) while requesting the latest version." +
" Are you using a custom Floodgate version?"
);
return; return;
} }
@@ -97,26 +95,34 @@ public class VersionSubcommand extends FloodgateSubCommand {
"Got an error from requesting the latest Floodgate version: {}", "Got an error from requesting the latest Floodgate version: {}",
response.toString() response.toString()
); );
sender.sendMessage(Message.UNEXPECTED_ERROR); sender.sendMessage(CommonCommandMessage.UNEXPECTED_ERROR);
return; return;
} }
int buildNumber = response.getAsInt(); int buildNumber = response.getAsInt();
if (buildNumber > Constants.BUILD_NUMBER) { if (buildNumber > Constants.BUILD_NUMBER) {
sender.sendMessage(String.format( sender.sendMessage(
COLOR_CHAR + "7There is a newer version of Floodgate available!\n" + Message.VERSION_OUTDATED,
COLOR_CHAR + "7You are " + COLOR_CHAR + "e%s " + COLOR_CHAR + "7builds behind.\n" + literal("count", buildNumber - Constants.BUILD_NUMBER),
COLOR_CHAR + "7Download the latest Floodgate version here: " + COLOR_CHAR + "b%s", literal("url", baseUrl));
buildNumber - Constants.BUILD_NUMBER, baseUrl
));
return; return;
} }
if (buildNumber == Constants.BUILD_NUMBER) { if (buildNumber == Constants.BUILD_NUMBER) {
sender.sendMessage(COLOR_CHAR + "aYou're running the latest version of Floodgate!"); sender.sendMessage(Message.VERSION_LATEST);
return; return;
} }
sender.sendMessage(COLOR_CHAR + "cCannot check version for custom Floodgate versions!"); sender.sendMessage(Message.VERSION_CUSTOM);
}); });
} }
public static final class Message {
public static final TranslatableMessage VERSION_INFO = new TranslatableMessage("floodgate.command.main.version.info", MessageType.NORMAL);
public static final TranslatableMessage VERSION_FETCH_INFO = new TranslatableMessage("floodgate.command.main.version.fetch.info", MessageType.INFO);
public static final TranslatableMessage VERSION_FETCH_ERROR = new TranslatableMessage("floodgate.command.main.version.fetch.error", MessageType.ERROR);
public static final TranslatableMessage VERSION_FETCH_NOT_FOUND = new TranslatableMessage("floodgate.command.main.version.fetch.not_found", MessageType.ERROR);
public static final TranslatableMessage VERSION_OUTDATED = new TranslatableMessage("floodgate.command.main.version.fetch.result.outdated", MessageType.NORMAL);
public static final TranslatableMessage VERSION_LATEST = new TranslatableMessage("floodgate.command.main.version.fetch.result.latest", MessageType.SUCCESS);
public static final TranslatableMessage VERSION_CUSTOM = new TranslatableMessage("floodgate.command.main.version.fetch.result.custom", MessageType.ERROR);
}
} }

View File

@@ -25,6 +25,8 @@
package org.geysermc.floodgate.core.connection; package org.geysermc.floodgate.core.connection;
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -38,7 +40,8 @@ import java.util.WeakHashMap;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.CommonPlatformMessages;
public abstract class ConnectionManager { public abstract class ConnectionManager {
private final Set<Connection> connections = Collections.synchronizedSet(new HashSet<>()); private final Set<Connection> connections = Collections.synchronizedSet(new HashSet<>());
@@ -93,9 +96,9 @@ public abstract class ConnectionManager {
pendingConnections.add(connection); pendingConnections.add(connection);
logger.translatedInfo( logger.translatedInfo(
"floodgate.ingame.login_name", CommonPlatformMessages.CONNECTION_LOGIN,
connection.javaUsername(), connection.javaUuid() literal("target", connection.javaUsername()),
); literal("target_uuid", connection.javaUuid()));
} }
public boolean addAcceptedConnection(Connection connection) { public boolean addAcceptedConnection(Connection connection) {
@@ -134,7 +137,9 @@ public abstract class ConnectionManager {
pendingConnections.remove(connection); pendingConnections.remove(connection);
uuidToConnection.remove(connection.javaUuid(), connection); uuidToConnection.remove(connection.javaUuid(), connection);
xuidToConnection.remove(connection.xuid(), connection); xuidToConnection.remove(connection.xuid(), connection);
logger.translatedInfo("floodgate.ingame.disconnect_name", connection.javaUsername()); logger.translatedInfo(
CommonPlatformMessages.CONNECTION_DISCONNECT,
literal("target", connection.javaUsername()));
} }
public Collection<Connection> acceptedConnections() { public Collection<Connection> acceptedConnections() {

View File

@@ -25,21 +25,25 @@
package org.geysermc.floodgate.core.connection; package org.geysermc.floodgate.core.connection;
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import lombok.NonNull; import lombok.NonNull;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.geysermc.floodgate.api.event.FloodgateEventBus; import org.geysermc.floodgate.api.event.FloodgateEventBus;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.addon.data.CommonNettyDataHandler; import org.geysermc.floodgate.core.addon.data.CommonNettyDataHandler;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.crypto.FloodgateDataCodec; import org.geysermc.floodgate.core.crypto.FloodgateDataCodec;
import org.geysermc.floodgate.core.crypto.exception.UnsupportedVersionException; import org.geysermc.floodgate.core.crypto.exception.UnsupportedVersionException;
import org.geysermc.floodgate.core.event.ConnectionJoinEvent; import org.geysermc.floodgate.core.event.ConnectionJoinEvent;
import org.geysermc.floodgate.core.link.CommonPlayerLink; import org.geysermc.floodgate.core.link.CommonPlayerLink;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.CommonPlatformMessages;
import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.Constants;
import org.geysermc.floodgate.core.util.InvalidFormatException; import org.geysermc.floodgate.core.util.InvalidFormatException;
import org.geysermc.floodgate.core.util.LanguageManager; import org.geysermc.floodgate.core.util.LanguageManager;
@@ -93,11 +97,11 @@ public final class FloodgateDataHandler {
private JoinResult canJoin(FloodgateConnection connection) { private JoinResult canJoin(FloodgateConnection connection) {
String disconnectReason = null; String disconnectReason = null;
if (config.playerLink().requireLink() && !connection.isLinked()) { if (config.playerLink().requireLink() && !connection.isLinked()) {
disconnectReason = languageManager.getString( disconnectReason = MiniMessage.miniMessage().serialize(
"floodgate.core.not_linked", CommonPlatformMessages.NOT_LINKED.translateMessage(
languageManager,
connection.languageCode(), connection.languageCode(),
Constants.LINK_INFO_URL literal("url", Constants.LINK_INFO_URL)));
);
} }
var event = new ConnectionJoinEvent(connection, disconnectReason); var event = new ConnectionJoinEvent(connection, disconnectReason);

View File

@@ -29,9 +29,13 @@ import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.core.platform.command.CommandUtil; import org.geysermc.floodgate.core.platform.command.CommandUtil;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.Placeholder;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage; import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
import org.geysermc.floodgate.core.util.MiniMessageUtils;
@Getter @Accessors(fluent = true) @Getter @Accessors(fluent = true)
public class UserAudience { public class UserAudience {
@@ -58,23 +62,30 @@ public class UserAudience {
return commandUtil.hasPermission(source(), permission); return commandUtil.hasPermission(source(), permission);
} }
public void sendMessage(String message) { /**
* This is only meant for development use, before the translations have been added
*/
public void sendRaw(String message, MessageType type, Placeholder... placeholders) {
sendMessage(MiniMessageUtils.formatMessage(message, type, placeholders));
}
public void sendMessage(Component message) {
commandUtil.sendMessage(source(), message); commandUtil.sendMessage(source(), message);
} }
public void sendMessage(TranslatableMessage message, Object... args) { public void sendMessage(TranslatableMessage message, Placeholder... placeholders) {
sendMessage(translateMessage(message, args)); sendMessage(translateMessage(message, placeholders));
} }
public void disconnect(@NonNull String reason) { public void disconnect(Component reason) {
commandUtil.kickPlayer(source(), reason); commandUtil.kickPlayer(source(), reason);
} }
public void disconnect(TranslatableMessage message, Object... args) { public void disconnect(TranslatableMessage message, Placeholder... args) {
disconnect(translateMessage(message, args)); disconnect(translateMessage(message, args));
} }
public String translateMessage(TranslatableMessage message, Object... args) { public Component translateMessage(TranslatableMessage message, Placeholder... args) {
return commandUtil.translateMessage(locale(), message, args); return commandUtil.translateMessage(locale(), message, args);
} }

View File

@@ -32,11 +32,11 @@ import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.api.GeyserApiBase; import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.database.entity.LinkRequest; import org.geysermc.floodgate.core.database.entity.LinkRequest;
import org.geysermc.floodgate.core.database.entity.LinkedPlayer; import org.geysermc.floodgate.core.database.entity.LinkedPlayer;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
public abstract class CommonPlayerLink { public abstract class CommonPlayerLink {
@Getter private boolean enabled; @Getter private boolean enabled;

View File

@@ -25,24 +25,34 @@
package org.geysermc.floodgate.core.link; package org.geysermc.floodgate.core.link;
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
import org.geysermc.floodgate.core.command.LinkAccountCommand.Message; import org.geysermc.floodgate.core.command.LinkAccountCommand.Message;
import org.geysermc.floodgate.core.platform.command.Placeholder;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
public class LinkVerificationException extends RuntimeException { public class LinkVerificationException extends RuntimeException {
public static final LinkVerificationException NO_LINK_REQUESTED = public static final LinkVerificationException NO_LINK_REQUESTED =
new LinkVerificationException(Message.NO_LINK_REQUESTED); new LinkVerificationException(Message.NO_LINK_REQUESTED, literal("command", "/linkaccount"));
public static final LinkVerificationException INVALID_CODE = public static final LinkVerificationException INVALID_CODE =
new LinkVerificationException(Message.INVALID_CODE); new LinkVerificationException(Message.INVALID_CODE, literal("command", "/linkaccount"));
public static final LinkVerificationException LINK_REQUEST_EXPIRED = public static final LinkVerificationException LINK_REQUEST_EXPIRED =
new LinkVerificationException(Message.LINK_REQUEST_EXPIRED); new LinkVerificationException(Message.LINK_REQUEST_EXPIRED, literal("command", "/linkaccount"));
private final Message message; private final TranslatableMessage message;
private final Placeholder[] placeholders;
private LinkVerificationException(Message message) { private LinkVerificationException(TranslatableMessage message, Placeholder... placeholders) {
super(null, null, true, false); super(null, null, true, false);
this.message = message; this.message = message;
this.placeholders = placeholders;
} }
public Message message() { public TranslatableMessage message() {
return message; return message;
} }
public Placeholder[] placeholders() {
return placeholders;
}
} }

View File

@@ -29,8 +29,8 @@ import io.micronaut.runtime.event.annotation.EventListener;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import java.util.Set; import java.util.Set;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.event.lifecycle.PostEnableEvent; import org.geysermc.floodgate.core.event.lifecycle.PostEnableEvent;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.listener.ListenerRegistration; import org.geysermc.floodgate.core.platform.listener.ListenerRegistration;
@Singleton @Singleton

View File

@@ -23,7 +23,11 @@
* @link https://github.com/GeyserMC/Floodgate * @link https://github.com/GeyserMC/Floodgate
*/ */
package org.geysermc.floodgate.api.logger; package org.geysermc.floodgate.core.logger;
import net.kyori.adventure.text.Component;
import org.geysermc.floodgate.core.platform.command.Placeholder;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
public interface FloodgateLogger { public interface FloodgateLogger {
String LOGGER_NAME = "Floodgate"; String LOGGER_NAME = "Floodgate";
@@ -61,7 +65,9 @@ public interface FloodgateLogger {
*/ */
void info(String message, Object... args); void info(String message, Object... args);
void translatedInfo(String message, Object... args); void info(Component message);
void translatedInfo(TranslatableMessage message, Placeholder... args);
/** /**
* Logs a debug message to the console, with 0 or more arguments. * Logs a debug message to the console, with 0 or more arguments.

View File

@@ -25,15 +25,17 @@
package org.geysermc.floodgate.core.logger; package org.geysermc.floodgate.core.logger;
import static org.geysermc.floodgate.core.util.MessageFormatter.format;
import io.micronaut.context.BeanProvider; import io.micronaut.context.BeanProvider;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.platform.command.Placeholder;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
import org.geysermc.floodgate.core.util.LanguageManager; import org.geysermc.floodgate.core.util.LanguageManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.helpers.MessageFormatter;
@Singleton @Singleton
public final class Slf4jFloodgateLogger implements FloodgateLogger { public final class Slf4jFloodgateLogger implements FloodgateLogger {
@@ -54,7 +56,7 @@ public final class Slf4jFloodgateLogger implements FloodgateLogger {
@Override @Override
public void error(String message, Throwable throwable, Object... args) { public void error(String message, Throwable throwable, Object... args) {
logger.error(format(message, args), throwable); logger.error(MessageFormatter.basicArrayFormat(message, args), throwable);
} }
@Override @Override
@@ -68,8 +70,16 @@ public final class Slf4jFloodgateLogger implements FloodgateLogger {
} }
@Override @Override
public void translatedInfo(String message, Object... args) { public void info(Component message) {
logger.info(languageManager.get().getLogString(message, args)); //todo check on other platforms if just serializing the component works.
// it does on Velocity
logger.info(MiniMessage.miniMessage().serialize(message));
}
@Override
public void translatedInfo(TranslatableMessage message, Placeholder... args) {
var manager = languageManager.get();
info(message.translateMessage(manager, manager.getDefaultLocale(), args));
} }
@Override @Override

View File

@@ -0,0 +1,12 @@
package org.geysermc.floodgate.core.platform;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
public class CommonPlatformMessages {
public static final TranslatableMessage CORE_FINISH = new TranslatableMessage("floodgate.core.finish");
public static final TranslatableMessage CONNECTION_LOGIN = new TranslatableMessage("floodgate.ingame.login_name");
public static final TranslatableMessage CONNECTION_DISCONNECT = new TranslatableMessage("floodgate.ingame.disconnect_name");
public static final TranslatableMessage NOT_LINKED = new TranslatableMessage("floodgate.core.not_linked", MessageType.ERROR);
}

View File

@@ -36,6 +36,7 @@ import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.api.GeyserApiBase; import org.geysermc.api.GeyserApiBase;
@@ -161,20 +162,24 @@ public abstract class CommandUtil {
* @param target the player that should receive the message * @param target the player that should receive the message
* @param message the message * @param message the message
*/ */
public abstract void sendMessage(Object target, String message); public abstract void sendMessage(Object target, Component message);
/** /**
* Kicks the given player using the given message as the kick reason. * Kicks the given player using the given message as the kick reason.
* *
* @param player the player that should be kicked * @param player the player that should be kicked
* @param message the command message * @param message the message
*/ */
public abstract void kickPlayer(Object player, String message); public abstract void kickPlayer(Object player, Component message);
public String translateMessage(String locale, TranslatableMessage message, Object... args) { public Component translateMessage(String locale, TranslatableMessage message, Placeholder... args) {
return message.translateMessage(manager, locale, args); return message.translateMessage(manager, locale, args);
} }
public LanguageManager languageManager() {
return manager;
}
/** /**
* Whitelist the given Bedrock player. * Whitelist the given Bedrock player.
* *

View File

@@ -0,0 +1,29 @@
package org.geysermc.floodgate.core.platform.command;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import org.checkerframework.checker.nullness.qual.Nullable;
public enum MessageType {
NONE(null, null),
NORMAL(null, NamedTextColor.AQUA),
INFO(NamedTextColor.YELLOW, NamedTextColor.AQUA),
SUCCESS(NamedTextColor.GREEN, NamedTextColor.GOLD),
ERROR(NamedTextColor.RED, NamedTextColor.GOLD);
private final TextColor primaryColor;
private final TextColor secondaryColor;
MessageType(@Nullable TextColor primaryColor, @Nullable TextColor secondaryColor) {
this.primaryColor = primaryColor;
this.secondaryColor = secondaryColor;
}
public @Nullable TextColor primaryColor() {
return primaryColor;
}
public @Nullable TextColor secondaryColor() {
return secondaryColor;
}
}

View File

@@ -0,0 +1,56 @@
package org.geysermc.floodgate.core.platform.command;
import java.util.Objects;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.minimessage.tag.Inserting;
import net.kyori.adventure.text.minimessage.tag.PreProcess;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.TagPattern;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.geysermc.floodgate.core.connection.audience.UserAudience;
public record Placeholder(@TagPattern String key, Tag tag) {
public static Placeholder dynamic(@TagPattern String key, String value) {
return new Placeholder(key, Tag.preProcessParsed(value));
}
public static Placeholder dynamic(@TagPattern String key, TranslatableMessage message, UserAudience audience) {
return dynamic(key, audience.commandUtil().languageManager().rawTranslation(message.toString(), audience.locale()));
}
public static Placeholder literal(@TagPattern String key, String value) {
return literal(key, Component.text(value));
}
public static Placeholder literal(@TagPattern String key, ComponentLike component) {
return new Placeholder(key, Tag.selfClosingInserting(component));
}
public static Placeholder literal(@TagPattern String key, Object value) {
return literal(key, Objects.toString(value));
}
public TagResolver resolver(MessageType type) {
return TagResolver.resolver(key, ($, context) -> {
var root = Component.empty();
// We've only looked at PreProcess and Inserting.
// We've excluded PreProcess because we expect the placeholders of the PreProcess to have the secondary
// color, not the PreProcess itself.
if (type.secondaryColor() != null && tag instanceof Inserting) {
root = root.color(type.secondaryColor());
}
if (tag instanceof PreProcess preProcess) {
root = root.append(context.deserialize(preProcess.value()));
} else if (tag instanceof Inserting inserting) {
root = root.append(inserting.value());
} else {
throw new UnsupportedOperationException("Only PreProcess and Inserting have been implemented!");
}
return Tag.selfClosingInserting(root);
});
}
}

View File

@@ -25,13 +25,13 @@
package org.geysermc.floodgate.core.platform.command; package org.geysermc.floodgate.core.platform.command;
import static org.geysermc.floodgate.core.util.Constants.COLOR_CHAR;
import static org.incendo.cloud.description.Description.description; import static org.incendo.cloud.description.Description.description;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import java.util.Locale;
import java.util.Set; import java.util.Set;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.command.util.Permission;
import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.connection.audience.UserAudience;
import org.incendo.cloud.Command; import org.incendo.cloud.Command;
@@ -68,19 +68,21 @@ public abstract class SubCommands implements FloodgateCommand {
} }
public void execute(CommandContext<UserAudience> context) { public void execute(CommandContext<UserAudience> context) {
StringBuilder helpMessage = new StringBuilder("Available subcommands are:\n"); var helpMessage = Component.text("Available subcommands are:").appendNewline(); //todo add translation
//todo this should probably follow MessageType as well
for (FloodgateSubCommand subCommand : subCommands) { for (FloodgateSubCommand subCommand : subCommands) {
var permission = subCommand.permission(); var permission = subCommand.permission();
if (permission == null || context.sender().hasPermission(permission.get())) { if (permission == null || context.sender().hasPermission(permission.get())) {
helpMessage.append('\n').append(COLOR_CHAR).append('b') var component = Component.newline()
.append(subCommand.name().toLowerCase(Locale.ROOT)) .append(Component.text(subCommand.name(), NamedTextColor.AQUA))
.append(COLOR_CHAR).append("f - ").append(COLOR_CHAR).append('7') .append(Component.text(" - "))
.append(subCommand.description()); .append(Component.text(subCommand.description(), NamedTextColor.GRAY));
helpMessage = helpMessage.append(component);
} }
} }
context.sender().sendMessage(helpMessage.toString()); context.sender().sendMessage(helpMessage);
} }
@PostConstruct @PostConstruct

View File

@@ -25,36 +25,49 @@
package org.geysermc.floodgate.core.platform.command; package org.geysermc.floodgate.core.platform.command;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.floodgate.core.util.LanguageManager; import org.geysermc.floodgate.core.util.LanguageManager;
/** /**
* TranslatableMessage is the interface for a message that can be translated. Messages are generally * TranslatableMessage is the common class for a message that can be translated
* implemented using enums.
*/ */
public interface TranslatableMessage { public class TranslatableMessage {
/** private final String rawMessage;
* Returns the message attached to the enum identifier private final String[] translateParts;
*/ private final MessageType type;
String getRawMessage();
/** public TranslatableMessage(String rawMessage, MessageType type) {
* Returns the parts of this message (getRawMessage() split on " ") this.rawMessage = rawMessage;
*/ this.translateParts = rawMessage.split(" ");
String[] getTranslateParts(); this.type = type;
}
public TranslatableMessage(String rawMessage) {
this(rawMessage, MessageType.NONE);
}
public Component translateMessage(LanguageManager manager, @Nullable String locale, Placeholder... placeholders) {
if (locale == null) {
locale = manager.getDefaultLocale();
}
default String translateMessage(LanguageManager manager, String locale, Object... args) {
String[] translateParts = getTranslateParts();
if (translateParts.length == 1) { if (translateParts.length == 1) {
return manager.getString(getRawMessage(), locale, args); return manager.getString(rawMessage, locale, type, placeholders);
} }
// todo only works when one section has arguments
StringBuilder builder = new StringBuilder(); Component complete = Component.empty();
for (int i = 0; i < translateParts.length; i++) { for (int i = 0; i < translateParts.length; i++) {
builder.append(manager.getString(translateParts[i], locale, args)); if (i != 0) {
if (translateParts.length != i + 1) { complete = complete.append(Component.text(' '));
builder.append(' '); }
} complete = complete.append(manager.getString(translateParts[i], locale, type, placeholders));
} }
return builder.toString(); return complete;
}
@Override
public String toString() {
return rawMessage;
} }
} }

View File

@@ -35,8 +35,8 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.impl.FormDefinition; import org.geysermc.cumulus.form.impl.FormDefinition;
import org.geysermc.cumulus.form.impl.FormDefinitions; import org.geysermc.cumulus.form.impl.FormDefinitions;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils; import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils;
import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel; import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel;

View File

@@ -28,7 +28,6 @@ package org.geysermc.floodgate.core.util;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import java.net.URL; import java.net.URL;
import java.text.MessageFormat;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
@@ -36,8 +35,15 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.Getter; import lombok.Getter;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.Inserting;
import net.kyori.adventure.text.minimessage.tag.PreProcess;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.Placeholder;
/** /**
* Manages translations for strings in Floodgate * Manages translations for strings in Floodgate
@@ -124,46 +130,38 @@ public final class LanguageManager {
return false; return false;
} }
/**
* Get a formatted language string with the default locale for Floodgate
*
* @param key language string to translate
* @param values values to put into the string
* @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);
}
/** /**
* Get a formatted language string with the given locale for Floodgate * Get a formatted language string with the given locale for Floodgate
* *
* @param key language string to translate * @param key language string to translate
* @param locale locale to translate to * @param locale locale to translate to
* @param values values to put into the string * @param type determines the scale of the message (and its arguments)
* @param placeholders values to put into the string
* @return translated string or "key arg1, arg2 (etc.)" 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) { public Component getString(String key, @Nullable String locale, MessageType type, Placeholder... placeholders) {
var translated = rawTranslation(key, locale);
if (translated == null) {
translated = formatNotFound(key, placeholders);
}
return MiniMessageUtils.formatMessage(translated, type, placeholders);
}
public String rawTranslation(String key, @Nullable String locale) {
Properties properties = localeMappings.get(locale); Properties properties = localeMappings.get(locale);
String formatString = null; String translated = null;
if (properties != null) { if (properties != null) {
formatString = properties.getProperty(key); translated = properties.getProperty(key);
} }
// try and get the key from the default locale // try and get the key from the default locale
if (formatString == null) { if (translated == null) {
properties = localeMappings.get(defaultLocale); properties = localeMappings.get(defaultLocale);
formatString = properties.getProperty(key); translated = properties.getProperty(key);
} }
// key wasn't found return translated;
if (formatString == null) {
return formatNotFound(key, values);
}
//todo don't use color codes in the strings
return MessageFormat.format(formatString.replace("'", "''").replace("&", "\u00a7"), values);
} }
/** /**
@@ -187,8 +185,16 @@ public final class LanguageManager {
return true; return true;
} }
private String formatNotFound(String key, Object... rawArgs) { private String formatNotFound(String key, Placeholder... placeholders) {
var args = Arrays.stream(rawArgs).map(Object::toString).collect(Collectors.joining(", ")); return key + ' ' + Arrays.stream(placeholders)
return key + " " + args; .map((resolver) -> {
if (resolver.tag() instanceof PreProcess preProcess) {
return resolver.key() + ": " + preProcess.value();
} else if (resolver.tag() instanceof Inserting inserting) {
return resolver.key() + ": " + MiniMessage.miniMessage().serialize(inserting.value());
}
return resolver.key() + " (unknown tag)";
})
.collect(Collectors.joining(", "));
} }
} }

View File

@@ -1,86 +0,0 @@
/*
* Copyright (c) 2019-2023 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.core.util;
public final class MessageFormatter {
private static final String DELIM_STR = "{}";
private static final int DELIM_LENGTH = DELIM_STR.length();
public static String format(String message, Object... arguments) {
// simple variant of slf4j's parameters.
if (arguments == null || arguments.length == 0) {
return message;
}
String[] args = new String[arguments.length];
for (int i = 0; i < arguments.length; i++) {
Object arg = arguments[i];
args[i] = arg != null ? arg.toString() : "null";
}
int previousIndex = -1;
int currentIndex;
StringBuilder stringBuilder =
new StringBuilder(message.length() + getArgsContentLength(args));
for (String argument : args) {
currentIndex = message.indexOf(DELIM_STR, previousIndex);
if (currentIndex == -1) {
// no parameter places left in message,
// we'll ignore the remaining parameters and return the message
if (previousIndex == -1) {
return message;
} else {
stringBuilder.append(message.substring(previousIndex));
return stringBuilder.toString();
}
}
if (previousIndex == -1) {
stringBuilder.append(message, 0, currentIndex);
} else {
stringBuilder.append(message, previousIndex, currentIndex);
}
stringBuilder.append(argument);
// we finished this argument, so we're past the current delimiter
previousIndex = currentIndex + DELIM_LENGTH;
}
if (previousIndex != message.length()) {
stringBuilder.append(message, previousIndex, message.length());
}
return stringBuilder.toString();
}
public static int getArgsContentLength(String... args) {
int length = 0;
for (String arg : args) {
length += arg.length();
}
return length;
}
}

View File

@@ -41,10 +41,10 @@ import org.bstats.charts.SimplePie;
import org.bstats.charts.SingleLineChart; import org.bstats.charts.SingleLineChart;
import org.bstats.json.JsonObjectBuilder; import org.bstats.json.JsonObjectBuilder;
import org.geysermc.api.GeyserApiBase; import org.geysermc.api.GeyserApiBase;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.config.FloodgateConfig.MetricsConfig; import org.geysermc.floodgate.core.config.FloodgateConfig.MetricsConfig;
import org.geysermc.floodgate.core.event.lifecycle.ShutdownEvent; import org.geysermc.floodgate.core.event.lifecycle.ShutdownEvent;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.util.PlatformUtils; import org.geysermc.floodgate.core.platform.util.PlatformUtils;
@Singleton @Singleton

View File

@@ -0,0 +1,25 @@
package org.geysermc.floodgate.core.util;
import java.util.Arrays;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.geysermc.floodgate.core.platform.command.MessageType;
import org.geysermc.floodgate.core.platform.command.Placeholder;
public final class MiniMessageUtils {
private MiniMessageUtils() {}
public static Component formatMessage(String message, MessageType type, Placeholder... placeholders) {
var styledResolvers = Arrays.stream(placeholders)
.map(placeholder -> placeholder.resolver(type))
.toArray(TagResolver[]::new);
var component = MiniMessage.miniMessage().deserialize(message, styledResolvers);
if (type.primaryColor() != null) {
component = Component.empty().color(type.primaryColor()).append(component);
}
return component;
}
}

View File

@@ -34,9 +34,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.event.lifecycle.PostEnableEvent; import org.geysermc.floodgate.core.event.lifecycle.PostEnableEvent;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
@Singleton @Singleton
public final class PostEnableMessages { public final class PostEnableMessages {
@@ -57,12 +57,13 @@ public final class PostEnableMessages {
} }
builder.append("**********************************"); builder.append("**********************************");
messages.add(MessageFormatter.format(builder.toString(), args)); messages.add(String.format(builder.toString(), args));
} }
@PostConstruct @PostConstruct
void registerPrefixMessages() { void registerPrefixMessages() {
String prefix = config.rawUsernamePrefix(); String prefix = config.rawUsernamePrefix();
//todo these messages should also be translated
if (prefix.isEmpty()) { if (prefix.isEmpty()) {
add(new String[]{ add(new String[]{
@@ -72,21 +73,21 @@ public final class PostEnableMessages {
}); });
} else if (!Utils.isUniquePrefix(prefix)) { } else if (!Utils.isUniquePrefix(prefix)) {
add(new String[]{ add(new String[]{
"The prefix you entered in your Floodgate config ({}) could lead to username conflicts!", "The prefix you entered in your Floodgate config (%s) could lead to username conflicts!",
"Should a Java player join with the username {}Notch, and a Bedrock player join as Notch (who will be given the name {}Notch), unwanted results will happen!", "Should a Java player join with the username %sNotch, and a Bedrock player join as Notch (who will be given the name %sNotch), unwanted results will happen!",
"We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *" "We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *"
}, prefix, prefix, prefix, prefix); }, prefix, prefix, prefix);
} }
if (prefix.length() >= 16) { if (prefix.length() >= 16) {
add(new String[]{ add(new String[]{
"The prefix you entered in your Floodgate config ({}) is longer than a Java username can be!", "The prefix you entered in your Floodgate config (%s) is longer than a Java username can be!",
"Because of this, we reset the prefix to the default Floodgate prefix (.)" "Because of this, we reset the prefix to the default Floodgate prefix (.)"
}, prefix); }, prefix);
} else if (prefix.length() > 2) { } else if (prefix.length() > 2) {
// we only have to warn them if we haven't replaced the prefix // we only have to warn them if we haven't replaced the prefix
add(new String[]{ add(new String[]{
"The prefix you entered in your Floodgate config ({}) is long! ({} characters)", "The prefix you entered in your Floodgate config (%s) is long! (%s characters)",
"A prefix is there to prevent username conflicts. However, a long prefix makes the chance of username conflicts higher.", "A prefix is there to prevent username conflicts. However, a long prefix makes the chance of username conflicts higher.",
"We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *" "We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *"
}, prefix, prefix.length()); }, prefix, prefix.length());

View File

@@ -34,8 +34,7 @@ public final class Constants {
public static final int CONFIG_VERSION = 3; public static final int CONFIG_VERSION = 3;
public static final char COLOR_CHAR = '\u00A7'; public static final int PROTOCOL_HEX_COLOR = 713; // added in 20w17a (1.16 snapshot)
public static final boolean DEBUG_MODE = false; public static final boolean DEBUG_MODE = false;
public static final boolean PRINT_ALL_PACKETS = false; public static final boolean PRINT_ALL_PACKETS = false;

View File

@@ -17,6 +17,8 @@ fastutil = "8.5.3"
cloud = "2.0.0-beta.2" cloud = "2.0.0-beta.2"
snakeyaml = "2.0" snakeyaml = "2.0"
bstats = "3.0.2" bstats = "3.0.2"
adventure = "4.16.0"
adventure-platform = "4.3.2"
# bungee # bungee
bungee = "master-SNAPSHOT" bungee = "master-SNAPSHOT"
@@ -59,6 +61,10 @@ cloud-core = { module = "org.incendo:cloud-core", version.ref = "cloud" }
snakeyaml = { module = "org.yaml:snakeyaml", version.ref = "snakeyaml" } snakeyaml = { module = "org.yaml:snakeyaml", version.ref = "snakeyaml" }
bstats = { module = "org.bstats:bstats-base", version.ref = "bstats" } bstats = { module = "org.bstats:bstats-base", version.ref = "bstats" }
adventure-text-minimessage = { module = "net.kyori:adventure-text-minimessage", version.ref = "adventure" }
adventure-platform-bukkit = { module = "net.kyori:adventure-platform-bukkit", version.ref = "adventure-platform"}
adventure-platform-bungee = { module = "net.kyori:adventure-platform-bungeecord", version.ref = "adventure-platform"}
micronaut-inject = { module = "io.micronaut:micronaut-inject" } micronaut-inject = { module = "io.micronaut:micronaut-inject" }
micronaut-inject-java = { module = "io.micronaut:micronaut-inject-java" } micronaut-inject-java = { module = "io.micronaut:micronaut-inject-java" }
micronaut-context = { module = "io.micronaut:micronaut-context" } micronaut-context = { module = "io.micronaut:micronaut-context" }

View File

@@ -5,6 +5,7 @@ dependencies {
compileOnlyApi(projects.isolation) compileOnlyApi(projects.isolation)
implementation(libs.cloud.paper) implementation(libs.cloud.paper)
implementation(libs.adventure.platform.bukkit)
compileOnlyApi(libs.paper.api) compileOnlyApi(libs.paper.api)
} }

View File

@@ -32,10 +32,10 @@ import jakarta.inject.Named;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.connection.DataSeeker; import org.geysermc.floodgate.core.connection.DataSeeker;
import org.geysermc.floodgate.core.connection.FloodgateDataHandler; import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
@Singleton @Singleton
public final class SpigotDataAddon implements InjectorAddon { public final class SpigotDataAddon implements InjectorAddon {

View File

@@ -34,13 +34,13 @@ import io.netty.util.AttributeKey;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.addon.data.CommonNettyDataHandler; import org.geysermc.floodgate.core.addon.data.CommonNettyDataHandler;
import org.geysermc.floodgate.core.addon.data.PacketBlocker; import org.geysermc.floodgate.core.addon.data.PacketBlocker;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.connection.DataSeeker; import org.geysermc.floodgate.core.connection.DataSeeker;
import org.geysermc.floodgate.core.connection.FloodgateDataHandler; import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
import org.geysermc.floodgate.core.connection.FloodgateDataHandler.HandleResult; import org.geysermc.floodgate.core.connection.FloodgateDataHandler.HandleResult;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.spigot.util.ClassNames; import org.geysermc.floodgate.spigot.util.ClassNames;
import org.geysermc.floodgate.spigot.util.ProxyUtils; import org.geysermc.floodgate.spigot.util.ProxyUtils;

View File

@@ -38,8 +38,8 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import lombok.Getter; import lombok.Getter;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.inject.CommonPlatformInjector; import org.geysermc.floodgate.core.inject.CommonPlatformInjector;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.util.ReflectionUtils; import org.geysermc.floodgate.core.util.ReflectionUtils;
import org.geysermc.floodgate.spigot.util.ClassNames; import org.geysermc.floodgate.spigot.util.ClassNames;

View File

@@ -32,10 +32,10 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.api.SimpleFloodgateApi; import org.geysermc.floodgate.core.api.SimpleFloodgateApi;
import org.geysermc.floodgate.core.connection.ConnectionManager; import org.geysermc.floodgate.core.connection.ConnectionManager;
import org.geysermc.floodgate.core.listener.McListener; import org.geysermc.floodgate.core.listener.McListener;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.util.LanguageManager; import org.geysermc.floodgate.core.util.LanguageManager;
@Singleton @Singleton

View File

@@ -29,7 +29,8 @@ import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import java.util.Collection; import java.util.Collection;
import java.util.UUID; import java.util.UUID;
import org.bukkit.OfflinePlayer; import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer;
import net.kyori.adventure.text.Component;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -114,15 +115,18 @@ public final class SpigotCommandUtil extends CommandUtil {
} }
@Override @Override
public void sendMessage(Object target, String message) { public void sendMessage(Object target, Component message) {
((CommandSender) target).sendMessage(message); ((CommandSender) target).sendMessage(message);
} }
@Override @Override
public void kickPlayer(Object player, String message) { public void kickPlayer(Object target, Component message) {
// can also be console // can also be console
if (player instanceof Player) { if (target instanceof Player player) {
versionSpecificMethods.schedule(() -> ((Player) player).kickPlayer(message), 0); versionSpecificMethods.schedule(() -> {
//todo don't include Adventure & use Component variants if/when there will be a Paper platform
player.kickPlayer(BukkitComponentSerializer.legacy().serialize( message));
}, 0);
} }
} }

View File

@@ -31,7 +31,7 @@ import java.util.UUID;
import org.geysermc.floodgate.api.handshake.HandshakeData; import org.geysermc.floodgate.api.handshake.HandshakeData;
import org.geysermc.floodgate.api.handshake.HandshakeHandler; import org.geysermc.floodgate.api.handshake.HandshakeHandler;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers; import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.util.BedrockData; import org.geysermc.floodgate.util.BedrockData;
@Singleton @Singleton

View File

@@ -32,11 +32,11 @@ import jakarta.inject.Named;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.addon.data.PacketBlocker; import org.geysermc.floodgate.core.addon.data.PacketBlocker;
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig; import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.core.connection.DataSeeker; import org.geysermc.floodgate.core.connection.DataSeeker;
import org.geysermc.floodgate.core.connection.FloodgateDataHandler; import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
@Singleton @Singleton
public final class VelocityDataAddon implements InjectorAddon { public final class VelocityDataAddon implements InjectorAddon {

View File

@@ -40,13 +40,13 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.addon.data.CommonNettyDataHandler; import org.geysermc.floodgate.core.addon.data.CommonNettyDataHandler;
import org.geysermc.floodgate.core.addon.data.PacketBlocker; import org.geysermc.floodgate.core.addon.data.PacketBlocker;
import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.connection.DataSeeker; import org.geysermc.floodgate.core.connection.DataSeeker;
import org.geysermc.floodgate.core.connection.FloodgateDataHandler; import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
import org.geysermc.floodgate.core.connection.FloodgateDataHandler.HandleResult; import org.geysermc.floodgate.core.connection.FloodgateDataHandler.HandleResult;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
public final class VelocityProxyDataHandler extends CommonNettyDataHandler { public final class VelocityProxyDataHandler extends CommonNettyDataHandler {
private static final Field HANDSHAKE; private static final Field HANDSHAKE;

View File

@@ -41,10 +41,10 @@ import jakarta.inject.Singleton;
import java.util.Collections; import java.util.Collections;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.geysermc.api.connection.Connection; import org.geysermc.api.connection.Connection;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.api.SimpleFloodgateApi; import org.geysermc.floodgate.core.api.SimpleFloodgateApi;
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig; import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.core.listener.McListener; import org.geysermc.floodgate.core.listener.McListener;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.util.LanguageManager; import org.geysermc.floodgate.core.util.LanguageManager;
import org.geysermc.floodgate.velocity.player.VelocityConnectionManager; import org.geysermc.floodgate.velocity.player.VelocityConnectionManager;

View File

@@ -39,8 +39,8 @@ import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import java.util.UUID; import java.util.UUID;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.listener.McListener; import org.geysermc.floodgate.core.listener.McListener;
import org.geysermc.floodgate.core.logger.FloodgateLogger;
import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils; import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils;
import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel; import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel;
import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel.Identity; import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel.Identity;

View File

@@ -109,14 +109,14 @@ public final class VelocityCommandUtil extends CommandUtil {
} }
@Override @Override
public void sendMessage(Object target, String message) { public void sendMessage(Object target, Component message) {
((CommandSource) target).sendMessage(Component.text(message)); ((CommandSource) target).sendMessage(message);
} }
@Override @Override
public void kickPlayer(Object player, String message) { public void kickPlayer(Object player, Component message) {
if (player instanceof Player) { if (player instanceof Player) {
((Player) player).disconnect(Component.text(message)); ((Player) player).disconnect(message);
} }
} }
} }