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:
@@ -5,6 +5,7 @@ dependencies {
|
||||
compileOnlyApi(projects.isolation)
|
||||
|
||||
implementation(libs.cloud.bungee)
|
||||
implementation(libs.adventure.platform.bungee)
|
||||
}
|
||||
|
||||
relocate("net.kyori")
|
||||
|
||||
@@ -32,11 +32,11 @@ import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
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.config.ProxyFloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.DataSeeker;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
|
||||
@Singleton
|
||||
public class BungeeDataAddon implements InjectorAddon {
|
||||
|
||||
@@ -38,12 +38,12 @@ import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.PacketWrapper;
|
||||
import net.md_5.bungee.protocol.packet.Handshake;
|
||||
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.PacketBlocker;
|
||||
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.DataSeeker;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.util.ReflectionUtils;
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
|
||||
@@ -39,9 +39,9 @@ import net.md_5.bungee.netty.PipelineUtils;
|
||||
import net.md_5.bungee.protocol.MinecraftEncoder;
|
||||
import net.md_5.bungee.protocol.Varint21LengthFieldExtraBufPrepender;
|
||||
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.core.inject.CommonPlatformInjector;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.util.ReflectionUtils;
|
||||
|
||||
@Singleton
|
||||
|
||||
@@ -42,11 +42,11 @@ import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.bungee.player.BungeeConnectionManager;
|
||||
import org.geysermc.floodgate.core.api.SimpleFloodgateApi;
|
||||
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
|
||||
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.SkinDataImpl;
|
||||
import org.geysermc.floodgate.core.util.LanguageManager;
|
||||
|
||||
@@ -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.event.EventHandler;
|
||||
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.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils;
|
||||
import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel;
|
||||
import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel.Identity;
|
||||
|
||||
@@ -42,9 +42,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent;
|
||||
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.skin.SkinApplyEventImpl;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.skin.SkinApplier;
|
||||
import org.geysermc.floodgate.core.skin.SkinDataImpl;
|
||||
import org.geysermc.floodgate.core.util.ReflectionUtils;
|
||||
|
||||
@@ -29,6 +29,8 @@ import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.util.Collection;
|
||||
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.ProxyServer;
|
||||
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.PlayerAudience;
|
||||
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.Utils;
|
||||
|
||||
@@ -106,15 +109,25 @@ public final class BungeeCommandUtil extends CommandUtil {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Object target, String message) {
|
||||
((CommandSender) target).sendMessage(message);
|
||||
public void sendMessage(Object target, Component 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
|
||||
public void kickPlayer(Object player, String message) {
|
||||
public void kickPlayer(Object target, Component message) {
|
||||
// can also be a console
|
||||
if (player instanceof ProxiedPlayer) {
|
||||
((ProxiedPlayer) player).disconnect(message);
|
||||
if (!(target instanceof ProxiedPlayer player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.getPendingConnection().getVersion() >= Constants.PROTOCOL_HEX_COLOR) {
|
||||
player.disconnect(BungeeComponentSerializer.get().serialize(message));
|
||||
return;
|
||||
}
|
||||
player.disconnect(BungeeComponentSerializer.legacy().serialize(message));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
|
||||
package org.geysermc.floodgate.bungee.util;
|
||||
|
||||
import static org.geysermc.floodgate.core.util.MessageFormatter.format;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
@@ -40,12 +38,13 @@ public class BungeeReflectionUtils {
|
||||
unsafeField.setAccessible(true);
|
||||
UNSAFE = (sun.misc.Unsafe) unsafeField.get(null);
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException(format(
|
||||
"Cannot initialize required reflection setup :/\nJava version: {}\nVendor: {} ({})",
|
||||
System.getProperty("java.version"),
|
||||
System.getProperty("java.vendor"),
|
||||
System.getProperty("java.vendor.url")
|
||||
), exception);
|
||||
throw new RuntimeException(
|
||||
String.format(
|
||||
"Cannot initialize required reflection setup :/\nJava version: %s\nVendor: %s (%s)",
|
||||
System.getProperty("java.version"),
|
||||
System.getProperty("java.vendor"),
|
||||
System.getProperty("java.vendor.url")),
|
||||
exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,12 +61,14 @@ public class BungeeReflectionUtils {
|
||||
} else {
|
||||
UNSAFE.putObject(object, offset, result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(format(
|
||||
"Java version: {}\nVendor: {} ({})",
|
||||
System.getProperty("java.version"),
|
||||
System.getProperty("java.vendor"),
|
||||
System.getProperty("java.vendor.url"), e));
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException(
|
||||
String.format(
|
||||
"Java version: %s\nVendor: %s (%s)",
|
||||
System.getProperty("java.version"),
|
||||
System.getProperty("java.vendor"),
|
||||
System.getProperty("java.vendor.url")),
|
||||
exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ dependencies {
|
||||
api(libs.cloud.core)
|
||||
api(libs.snakeyaml)
|
||||
api(libs.bstats)
|
||||
api(libs.adventure.text.minimessage)
|
||||
|
||||
api(libs.micronaut.inject)
|
||||
annotationProcessor(libs.micronaut.inject.java)
|
||||
|
||||
@@ -39,7 +39,6 @@ import org.geysermc.floodgate.api.InstanceHolder;
|
||||
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||
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.core.config.ConfigLoader;
|
||||
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.lifecycle.PostEnableEvent;
|
||||
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.library.LibraryManager;
|
||||
|
||||
@@ -98,8 +100,9 @@ public abstract class FloodgatePlatform implements IsolatedPlatform {
|
||||
Geyser.set(api);
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
context.getBean(FloodgateLogger.class)
|
||||
.translatedInfo("floodgate.core.finish", endTime - startTime);
|
||||
context.getBean(FloodgateLogger.class).translatedInfo(
|
||||
CommonPlatformMessages.CORE_FINISH,
|
||||
Placeholder.literal("time_in_ms", endTime - startTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,11 +31,11 @@ import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
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.ChannelOutDebugHandler;
|
||||
import org.geysermc.floodgate.core.addon.debug.StateChangeDetector;
|
||||
import org.geysermc.floodgate.core.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.util.Utils;
|
||||
|
||||
@Singleton
|
||||
|
||||
@@ -35,13 +35,13 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.connection.DataSeeker;
|
||||
import org.geysermc.floodgate.core.connection.DataSeeker.DataSeekerResult;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateDataHandler.HandleResult;
|
||||
import org.geysermc.floodgate.core.crypto.exception.UnsupportedVersionException;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.util.InvalidFormatException;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -30,7 +30,7 @@ import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
|
||||
@Sharable
|
||||
public final class ChannelInDebugHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
||||
|
||||
@@ -30,7 +30,7 @@ import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
|
||||
@Sharable
|
||||
public final class ChannelOutDebugHandler extends MessageToByteEncoder<ByteBuf> {
|
||||
|
||||
@@ -30,7 +30,7 @@ import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
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.Utils;
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ import org.geysermc.cumulus.form.Form;
|
||||
import org.geysermc.cumulus.form.util.FormBuilder;
|
||||
import org.geysermc.floodgate.api.InstanceHolder;
|
||||
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.connection.ConnectionManager;
|
||||
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.channel.FormChannel;
|
||||
import org.geysermc.floodgate.core.pluginmessage.channel.TransferChannel;
|
||||
|
||||
@@ -25,32 +25,19 @@
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Messages (or part of messages) that are used in two or more commands and thus are 'commonly
|
||||
* used'
|
||||
*/
|
||||
@Getter
|
||||
public enum CommonCommandMessage implements TranslatableMessage {
|
||||
LINKING_DISABLED("floodgate.commands.linking_disabled"),
|
||||
NOT_A_PLAYER("floodgate.commands.not_a_player"),
|
||||
CHECK_CONSOLE("floodgate.commands.check_console"),
|
||||
IS_LINKED_ERROR("floodgate.commands.is_linked_error"),
|
||||
LOCAL_LINKING_NOTICE("floodgate.commands.local_linking_notice"),
|
||||
GLOBAL_LINKING_NOTICE("floodgate.commands.global_linking_notice");
|
||||
|
||||
private final String rawMessage;
|
||||
private final String[] translateParts;
|
||||
|
||||
CommonCommandMessage(String rawMessage) {
|
||||
this.rawMessage = rawMessage;
|
||||
this.translateParts = rawMessage.split(" ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getRawMessage();
|
||||
}
|
||||
public class CommonCommandMessage {
|
||||
public static final TranslatableMessage LINKING_DISABLED = new TranslatableMessage("floodgate.commands.linking_disabled", MessageType.ERROR);
|
||||
public static final TranslatableMessage NOT_A_PLAYER = new TranslatableMessage("floodgate.commands.not_a_player", MessageType.ERROR);
|
||||
public static final TranslatableMessage CHECK_CONSOLE = new TranslatableMessage("floodgate.commands.check_console");
|
||||
public static final TranslatableMessage UNEXPECTED_ERROR = new TranslatableMessage("floodgate.commands.unexpected_error " + CommonCommandMessage.CHECK_CONSOLE, MessageType.ERROR);
|
||||
public static final TranslatableMessage IS_LINKED_ERROR = new TranslatableMessage("floodgate.commands.is_linked_error", MessageType.ERROR);
|
||||
public static final TranslatableMessage LOCAL_LINKING_NOTICE = new TranslatableMessage("floodgate.commands.local_linking_notice", MessageType.INFO);
|
||||
public static final TranslatableMessage GLOBAL_LINKING_NOTICE = new TranslatableMessage("floodgate.commands.global_linking_notice", MessageType.INFO);
|
||||
}
|
||||
|
||||
@@ -25,13 +25,12 @@
|
||||
|
||||
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 jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
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.command.util.Permission;
|
||||
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.link.CommonPlayerLink;
|
||||
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.MessageType;
|
||||
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
|
||||
import org.geysermc.floodgate.core.util.Constants;
|
||||
import org.geysermc.floodgate.core.util.Utils;
|
||||
@@ -75,11 +76,15 @@ public final class LinkAccountCommand implements FloodgateCommand {
|
||||
if (!linkState.globalLinkingEnabled()) {
|
||||
sender.sendMessage(CommonCommandMessage.LINKING_DISABLED);
|
||||
} else {
|
||||
sender.sendMessage(CommonCommandMessage.GLOBAL_LINKING_NOTICE, Constants.LINK_INFO_URL);
|
||||
sender.sendMessage(
|
||||
CommonCommandMessage.GLOBAL_LINKING_NOTICE,
|
||||
literal("url", Constants.LINK_INFO_URL));
|
||||
}
|
||||
return;
|
||||
} 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");
|
||||
@@ -89,7 +94,7 @@ public final class LinkAccountCommand implements FloodgateCommand {
|
||||
// when the player is a Bedrock player
|
||||
if (api.isBedrockPlayer(sender.uuid())) {
|
||||
if (!context.contains("code")) {
|
||||
sender.sendMessage(Message.BEDROCK_USAGE);
|
||||
sender.sendMessage(Message.BEDROCK_USAGE, literal("command", "/linkaccount <gamertag>"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,20 +126,23 @@ public final class LinkAccountCommand implements FloodgateCommand {
|
||||
)
|
||||
.whenComplete(($, throwable) -> {
|
||||
if (throwable instanceof LinkVerificationException exception) {
|
||||
sender.sendMessage(exception.message());
|
||||
sender.sendMessage(exception.message(), exception.placeholders());
|
||||
return;
|
||||
}
|
||||
if (throwable != null) {
|
||||
sender.sendMessage(Message.LINK_REQUEST_ERROR);
|
||||
return;
|
||||
}
|
||||
sender.disconnect(Message.LINK_REQUEST_COMPLETED, targetName);
|
||||
sender.disconnect(
|
||||
Message.LINK_REQUEST_COMPLETED,
|
||||
literal("target", targetName),
|
||||
literal("command", "/unlinkaccount"));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.contains("code")) {
|
||||
sender.sendMessage(Message.JAVA_USAGE);
|
||||
sender.sendMessage(Message.JAVA_USAGE, literal("command", "/linkaccount <gamertag>"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -147,7 +155,11 @@ public final class LinkAccountCommand implements FloodgateCommand {
|
||||
sender.sendMessage(Message.LINK_REQUEST_ERROR);
|
||||
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());
|
||||
}
|
||||
|
||||
@Getter
|
||||
public enum Message implements TranslatableMessage {
|
||||
ALREADY_LINKED("floodgate.command.link_account.already_linked"),
|
||||
JAVA_USAGE("floodgate.command.link_account.java_usage"),
|
||||
LINK_REQUEST_CREATED("floodgate.command.link_account.link_request_created"),
|
||||
BEDROCK_USAGE("floodgate.command.link_account.bedrock_usage"),
|
||||
LINK_REQUEST_EXPIRED("floodgate.command.link_account.link_request_expired"),
|
||||
LINK_REQUEST_COMPLETED("floodgate.command.link_account.link_request_completed"),
|
||||
LINK_REQUEST_ERROR("floodgate.command.link_request.error " + CommonCommandMessage.CHECK_CONSOLE),
|
||||
INVALID_CODE("floodgate.command.link_account.invalid_code"),
|
||||
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(" ");
|
||||
}
|
||||
public static final class Message {
|
||||
public static final TranslatableMessage ALREADY_LINKED = new TranslatableMessage("floodgate.command.link_account.already_linked", MessageType.ERROR);
|
||||
public static final TranslatableMessage JAVA_USAGE = new TranslatableMessage("floodgate.command.link_account.java_usage", MessageType.ERROR);
|
||||
public static final TranslatableMessage LINK_REQUEST_CREATED = new TranslatableMessage("floodgate.command.link_account.link_request_created", MessageType.SUCCESS);
|
||||
public static final TranslatableMessage BEDROCK_USAGE = new TranslatableMessage("floodgate.command.link_account.bedrock_usage", MessageType.ERROR);
|
||||
public static final TranslatableMessage LINK_REQUEST_EXPIRED = new TranslatableMessage("floodgate.command.link_account.link_request_expired", MessageType.ERROR);
|
||||
public static final TranslatableMessage LINK_REQUEST_COMPLETED = new TranslatableMessage("floodgate.command.link_account.link_request_completed", MessageType.SUCCESS);
|
||||
public static final TranslatableMessage LINK_REQUEST_ERROR = new TranslatableMessage("floodgate.command.link_account.link_request_error " + CommonCommandMessage.CHECK_CONSOLE, MessageType.ERROR);
|
||||
public static final TranslatableMessage INVALID_CODE = new TranslatableMessage("floodgate.command.link_account.invalid_code", MessageType.ERROR);
|
||||
public static final TranslatableMessage NO_LINK_REQUESTED = new TranslatableMessage("floodgate.command.link_account.no_link_requested", MessageType.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,15 +25,17 @@
|
||||
|
||||
package org.geysermc.floodgate.core.command;
|
||||
|
||||
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.floodgate.core.command.util.Permission;
|
||||
import org.geysermc.floodgate.core.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.audience.UserAudience;
|
||||
import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience;
|
||||
import org.geysermc.floodgate.core.link.CommonPlayerLink;
|
||||
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.util.Constants;
|
||||
import org.incendo.cloud.Command;
|
||||
@@ -63,11 +65,13 @@ public final class UnlinkAccountCommand implements FloodgateCommand {
|
||||
if (!linkState.globalLinkingEnabled()) {
|
||||
sender.sendMessage(CommonCommandMessage.LINKING_DISABLED);
|
||||
} else {
|
||||
sender.sendMessage(CommonCommandMessage.GLOBAL_LINKING_NOTICE, Constants.LINK_INFO_URL);
|
||||
sender.sendMessage(
|
||||
CommonCommandMessage.GLOBAL_LINKING_NOTICE,
|
||||
literal("url", Constants.LINK_INFO_URL));
|
||||
}
|
||||
return;
|
||||
} 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())
|
||||
@@ -101,18 +105,9 @@ public final class UnlinkAccountCommand implements FloodgateCommand {
|
||||
(linkConfig.enableOwnLinking() || linkConfig.enableGlobalLinking());
|
||||
}
|
||||
|
||||
@Getter
|
||||
public enum Message implements TranslatableMessage {
|
||||
NOT_LINKED("floodgate.command.unlink_account.not_linked"),
|
||||
UNLINK_SUCCESS("floodgate.command.unlink_account.unlink_success"),
|
||||
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(" ");
|
||||
}
|
||||
public static final class Message {
|
||||
public static final TranslatableMessage NOT_LINKED = new TranslatableMessage("floodgate.command.unlink_account.not_linked", MessageType.ERROR);
|
||||
public static final TranslatableMessage UNLINK_SUCCESS = new TranslatableMessage("floodgate.command.unlink_account.unlink_success", MessageType.SUCCESS);
|
||||
public static final TranslatableMessage UNLINK_ERROR = new TranslatableMessage("floodgate.command.unlink_account.error " + CommonCommandMessage.CHECK_CONSOLE, MessageType.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,20 +25,22 @@
|
||||
|
||||
package org.geysermc.floodgate.core.command;
|
||||
|
||||
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
|
||||
|
||||
import io.micronaut.http.client.exceptions.HttpClientResponseException;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
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.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.config.ProxyFloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.audience.ProfileAudience;
|
||||
import org.geysermc.floodgate.core.connection.audience.UserAudience;
|
||||
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.FloodgateCommand;
|
||||
import org.geysermc.floodgate.core.platform.command.MessageType;
|
||||
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
@@ -76,7 +78,7 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
String name = profile.username();
|
||||
|
||||
if (name == null && uuid == null) {
|
||||
sender.sendMessage(Message.UNEXPECTED_ERROR);
|
||||
sender.sendMessage(CommonCommandMessage.UNEXPECTED_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -90,16 +92,15 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
|
||||
if (add) {
|
||||
if (commandUtil.whitelistPlayer(uuid, "unknown")) {
|
||||
sender.sendMessage(Message.PLAYER_ADDED, uuid.toString());
|
||||
sender.sendMessage(Message.PLAYER_ADDED, literal("target", uuid.toString()));
|
||||
} else {
|
||||
sender.sendMessage(Message.PLAYER_ALREADY_WHITELISTED,
|
||||
uuid.toString());
|
||||
sender.sendMessage(Message.PLAYER_ALREADY_WHITELISTED, literal("target", uuid.toString()));
|
||||
}
|
||||
} else {
|
||||
if (commandUtil.removePlayerFromWhitelist(uuid, "unknown")) {
|
||||
sender.sendMessage(Message.PLAYER_REMOVED, uuid.toString());
|
||||
sender.sendMessage(Message.PLAYER_REMOVED, literal("target", uuid.toString()));
|
||||
} else {
|
||||
sender.sendMessage(Message.PLAYER_NOT_WHITELISTED, uuid.toString());
|
||||
sender.sendMessage(Message.PLAYER_NOT_WHITELISTED, literal("target", uuid.toString()));
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -132,7 +133,7 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
error.printStackTrace();
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(Message.UNEXPECTED_ERROR);
|
||||
sender.sendMessage(CommonCommandMessage.UNEXPECTED_ERROR);
|
||||
|
||||
//todo proper non-200 status handler
|
||||
// var response = exception.getResponse().getBody(UnsuccessfulResponse.class);
|
||||
@@ -149,7 +150,7 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
|
||||
Long xuid = result.xuid();
|
||||
if (xuid == null) {
|
||||
sender.sendMessage(Message.USER_NOT_FOUND);
|
||||
sender.sendMessage(Message.ACCOUNT_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -158,16 +159,15 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
try {
|
||||
if (add) {
|
||||
if (commandUtil.whitelistPlayer(xuid, correctName)) {
|
||||
sender.sendMessage(Message.PLAYER_ADDED, strippedName);
|
||||
sender.sendMessage(Message.PLAYER_ADDED, literal("target", strippedName));
|
||||
} else {
|
||||
sender.sendMessage(Message.PLAYER_ALREADY_WHITELISTED,
|
||||
strippedName);
|
||||
sender.sendMessage(Message.PLAYER_ALREADY_WHITELISTED, literal("target", strippedName));
|
||||
}
|
||||
} else {
|
||||
if (commandUtil.removePlayerFromWhitelist(xuid, correctName)) {
|
||||
sender.sendMessage(Message.PLAYER_REMOVED, strippedName);
|
||||
sender.sendMessage(Message.PLAYER_REMOVED, literal("target", strippedName));
|
||||
} else {
|
||||
sender.sendMessage(Message.PLAYER_NOT_WHITELISTED, strippedName);
|
||||
sender.sendMessage(Message.PLAYER_NOT_WHITELISTED, literal("target", strippedName));
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
@@ -185,23 +185,13 @@ public class WhitelistCommand implements FloodgateCommand {
|
||||
return !(config instanceof ProxyFloodgateConfig);
|
||||
}
|
||||
|
||||
@Getter
|
||||
public enum Message implements TranslatableMessage {
|
||||
INVALID_USERNAME("floodgate.command.fwhitelist.invalid_username"),
|
||||
API_UNAVAILABLE("floodgate.command.fwhitelist.api_unavailable " + CommonCommandMessage.CHECK_CONSOLE),
|
||||
USER_NOT_FOUND("floodgate.command.fwhitelist.user_not_found"),
|
||||
PLAYER_ADDED("floodgate.command.fwhitelist.player_added"),
|
||||
PLAYER_REMOVED("floodgate.command.fwhitelist.player_removed"),
|
||||
PLAYER_ALREADY_WHITELISTED("floodgate.command.fwhitelist.player_already_whitelisted"),
|
||||
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(" ");
|
||||
}
|
||||
public static final class Message {
|
||||
public static final TranslatableMessage INVALID_USERNAME = new TranslatableMessage("floodgate.command.fwhitelist.invalid_username", MessageType.ERROR);
|
||||
public static final TranslatableMessage API_UNAVAILABLE = new TranslatableMessage("floodgate.command.fwhitelist.api_unavailable " + CommonCommandMessage.CHECK_CONSOLE, MessageType.ERROR);
|
||||
public static final TranslatableMessage ACCOUNT_NOT_FOUND = new TranslatableMessage("floodgate.command.fwhitelist.account_not_found", MessageType.ERROR);
|
||||
public static final TranslatableMessage PLAYER_ADDED = new TranslatableMessage("floodgate.command.fwhitelist.player_added", MessageType.SUCCESS);
|
||||
public static final TranslatableMessage PLAYER_REMOVED = new TranslatableMessage("floodgate.command.fwhitelist.player_removed", MessageType.SUCCESS);
|
||||
public static final TranslatableMessage PLAYER_ALREADY_WHITELISTED = new TranslatableMessage("floodgate.command.fwhitelist.player_already_whitelisted", MessageType.NORMAL);
|
||||
public static final TranslatableMessage PLAYER_NOT_WHITELISTED = new TranslatableMessage("floodgate.command.fwhitelist.player_not_whitelisted", MessageType.NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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.Singleton;
|
||||
@@ -8,15 +9,18 @@ import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
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.LinkAccountCommand;
|
||||
import org.geysermc.floodgate.core.command.linkedaccounts.LinkedAccountsCommand.LinkedAccountsCommonMessage;
|
||||
import org.geysermc.floodgate.core.command.util.Permission;
|
||||
import org.geysermc.floodgate.core.connection.audience.ProfileAudience;
|
||||
import org.geysermc.floodgate.core.connection.audience.UserAudience;
|
||||
import org.geysermc.floodgate.core.http.ProfileFetcher;
|
||||
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.MessageType;
|
||||
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
|
||||
import org.geysermc.floodgate.core.util.Constants;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
@@ -49,7 +53,7 @@ final class AddLinkedAccountCommand extends FloodgateSubCommand {
|
||||
|
||||
var linking = optionalLinking.get();
|
||||
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");
|
||||
@@ -61,7 +65,10 @@ final class AddLinkedAccountCommand extends FloodgateSubCommand {
|
||||
|
||||
if (bedrockRef.get().uuid() == null) {
|
||||
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) {
|
||||
futures.add(fetcher.fetchUniqueIdFor(javaRef.get().username()).thenAccept(javaRef::set));
|
||||
}
|
||||
@@ -72,10 +79,16 @@ final class AddLinkedAccountCommand extends FloodgateSubCommand {
|
||||
var java = javaRef.get();
|
||||
|
||||
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) {
|
||||
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) -> {
|
||||
@@ -84,8 +97,18 @@ final class AddLinkedAccountCommand extends FloodgateSubCommand {
|
||||
logger.error("Exception while manually linking accounts", throwable);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
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.Singleton;
|
||||
import java.util.Optional;
|
||||
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.linkedaccounts.LinkedAccountsCommand.LinkedAccountsCommonMessage;
|
||||
import org.geysermc.floodgate.core.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.audience.ProfileAudience;
|
||||
import org.geysermc.floodgate.core.connection.audience.UserAudience;
|
||||
import org.geysermc.floodgate.core.http.ProfileFetcher;
|
||||
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.MessageType;
|
||||
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
|
||||
import org.geysermc.floodgate.core.util.Constants;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
@@ -43,22 +49,26 @@ final class InfoLinkedAccountCommand extends FloodgateSubCommand {
|
||||
|
||||
var linking = optionalLinking.get();
|
||||
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");
|
||||
String gamertagInput;
|
||||
final boolean bedrock;
|
||||
|
||||
var future = CompletableFuture.completedFuture(playerInput);
|
||||
if (playerInput.uuid() == null) {
|
||||
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;
|
||||
} else {
|
||||
gamertagInput = null;
|
||||
bedrock = false;
|
||||
future = fetcher.fetchUniqueIdFor(playerInput.username());
|
||||
}
|
||||
} else {
|
||||
gamertagInput = null;
|
||||
bedrock = playerInput.uuid().getMostSignificantBits() == 0;
|
||||
}
|
||||
|
||||
@@ -71,13 +81,16 @@ final class InfoLinkedAccountCommand extends FloodgateSubCommand {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
linking.fetchLink(result.uuid()).whenComplete((link, error) -> {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@@ -85,13 +98,43 @@ final class InfoLinkedAccountCommand extends FloodgateSubCommand {
|
||||
var usernameOrUniqueId = playerInput.username() != null ? playerInput.username() : playerInput.uuid();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
sender.sendMessage("Link info for %s user %s:\n%s"
|
||||
.formatted(platform, usernameOrUniqueId, LinkedAccountsCommand.linkInfoMessage(link)));
|
||||
CompletableFuture<ProfileAudience> gamertagFetch =
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ package org.geysermc.floodgate.core.command.linkedaccounts;
|
||||
|
||||
import jakarta.inject.Singleton;
|
||||
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.TranslatableMessage;
|
||||
|
||||
@Singleton
|
||||
final class LinkedAccountsCommand extends SubCommands {
|
||||
@@ -11,9 +12,8 @@ final class LinkedAccountsCommand extends SubCommands {
|
||||
super("linkedaccounts", "Manage locally linked accounts", Permission.COMMAND_LINKED);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
static String linkInfoMessage(LinkedPlayer player) {
|
||||
return "Java UUID: %s\nJava username: %s\nBedrock UUID: %s"
|
||||
.formatted(player.javaUniqueId(), player.javaUsername(), player.bedrockId());
|
||||
public static final class LinkedAccountsCommonMessage {
|
||||
public static final TranslatableMessage NOT_FOUND = new TranslatableMessage("floodgate.command.linkedaccounts.common.not_found", MessageType.ERROR);
|
||||
public static final TranslatableMessage LINK_INFO = new TranslatableMessage("floodgate.command.linkedaccounts.common.link_info");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
package org.geysermc.floodgate.core.command.linkedaccounts;
|
||||
|
||||
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
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.LinkAccountCommand;
|
||||
import org.geysermc.floodgate.core.command.linkedaccounts.LinkedAccountsCommand.LinkedAccountsCommonMessage;
|
||||
import org.geysermc.floodgate.core.command.util.Permission;
|
||||
import org.geysermc.floodgate.core.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.audience.ProfileAudience;
|
||||
import org.geysermc.floodgate.core.connection.audience.UserAudience;
|
||||
import org.geysermc.floodgate.core.http.ProfileFetcher;
|
||||
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.MessageType;
|
||||
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
|
||||
import org.geysermc.floodgate.core.util.Constants;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
@@ -45,7 +50,7 @@ final class RemoveLinkedAccountCommand extends FloodgateSubCommand {
|
||||
|
||||
var linking = optionalLinking.get();
|
||||
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");
|
||||
@@ -73,8 +78,10 @@ final class RemoveLinkedAccountCommand extends FloodgateSubCommand {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -84,9 +91,15 @@ final class RemoveLinkedAccountCommand extends FloodgateSubCommand {
|
||||
logger.error("Exception while manually linking accounts", error);
|
||||
return;
|
||||
}
|
||||
sender.sendMessage("You've successfully unlinked %s user %s"
|
||||
.formatted(platform, playerInput.username()));
|
||||
sender.sendMessage(
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
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 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.connection.audience.UserAudience;
|
||||
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.HttpClient;
|
||||
import org.geysermc.floodgate.core.util.HttpClient.HttpResponse;
|
||||
@@ -62,10 +64,10 @@ final class FirewallCheckSubcommand extends FloodgateSubCommand {
|
||||
executeChecks(
|
||||
globalApiCheck(sender)
|
||||
).whenComplete((response, $) ->
|
||||
sender.sendMessage(String.format(
|
||||
COLOR_CHAR + "eThe checks have finished. %s/%s were successful",
|
||||
response.left(), response.left() + response.right()
|
||||
))
|
||||
sender.sendMessage(
|
||||
Message.FIREWALL_RESULT,
|
||||
literal("successful", response.left()),
|
||||
literal("total", response.left() + response.right()))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -88,14 +90,14 @@ final class FirewallCheckSubcommand extends FloodgateSubCommand {
|
||||
private BooleanSupplier executeFirewallText(
|
||||
UserAudience sender, String name, Runnable runnable) {
|
||||
return () -> {
|
||||
sender.sendMessage(COLOR_CHAR + "eTesting " + name + "...");
|
||||
sender.sendMessage(Message.CHECK_START, literal("target", name));
|
||||
try {
|
||||
runnable.run();
|
||||
sender.sendMessage(COLOR_CHAR + "aWas able to connect to " + name + "!");
|
||||
sender.sendMessage(Message.CHECK_SUCCESS, literal("target", name));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
sender.sendMessage(COLOR_CHAR + "cFailed to connect:");
|
||||
sender.sendMessage(Utils.getStackTrace(e));
|
||||
} catch (Exception exception) {
|
||||
sender.sendMessage(Message.CHECK_FAILED, literal("target", name));
|
||||
sender.sendRaw(Utils.getStackTrace(exception), MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -117,4 +119,11 @@ final class FirewallCheckSubcommand extends FloodgateSubCommand {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,16 +25,18 @@
|
||||
|
||||
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 jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.command.WhitelistCommand.Message;
|
||||
import org.geysermc.floodgate.core.command.CommonCommandMessage;
|
||||
import org.geysermc.floodgate.core.command.util.Permission;
|
||||
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.MessageType;
|
||||
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
|
||||
import org.geysermc.floodgate.core.util.Constants;
|
||||
import org.geysermc.floodgate.core.util.HttpClient;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
@@ -56,12 +58,11 @@ public class VersionSubcommand extends FloodgateSubCommand {
|
||||
@Override
|
||||
public void execute(CommandContext<UserAudience> context) {
|
||||
UserAudience sender = context.sender();
|
||||
sender.sendMessage(String.format(
|
||||
COLOR_CHAR + "7You're currently on " + COLOR_CHAR + "b%s" +
|
||||
COLOR_CHAR + "7 (branch: " + COLOR_CHAR + "b%s" + COLOR_CHAR + "7)\n" +
|
||||
COLOR_CHAR + "eFetching latest build info...",
|
||||
Constants.FULL_VERSION, Constants.GIT_BRANCH
|
||||
));
|
||||
sender.sendMessage(
|
||||
Message.VERSION_INFO,
|
||||
literal("version", Constants.FULL_VERSION),
|
||||
literal("branch", Constants.GIT_BRANCH));
|
||||
sender.sendMessage(Message.VERSION_FETCH_INFO);
|
||||
|
||||
String baseUrl = String.format(
|
||||
"https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/%s/lastSuccessfulBuild/",
|
||||
@@ -73,7 +74,7 @@ public class VersionSubcommand extends FloodgateSubCommand {
|
||||
JsonElement.class
|
||||
).whenComplete((result, error) -> {
|
||||
if (error != null) {
|
||||
sender.sendMessage(COLOR_CHAR + "cCould not retrieve latest version info!");
|
||||
sender.sendMessage(Message.VERSION_FETCH_ERROR);
|
||||
error.printStackTrace();
|
||||
return;
|
||||
}
|
||||
@@ -84,10 +85,7 @@ public class VersionSubcommand extends FloodgateSubCommand {
|
||||
logger.info("{}", result.getHttpCode());
|
||||
|
||||
if (result.getHttpCode() == 404) {
|
||||
sender.sendMessage(
|
||||
COLOR_CHAR + "cGot a 404 (not found) while requesting the latest version." +
|
||||
" Are you using a custom Floodgate version?"
|
||||
);
|
||||
sender.sendMessage(Message.VERSION_FETCH_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -97,26 +95,34 @@ public class VersionSubcommand extends FloodgateSubCommand {
|
||||
"Got an error from requesting the latest Floodgate version: {}",
|
||||
response.toString()
|
||||
);
|
||||
sender.sendMessage(Message.UNEXPECTED_ERROR);
|
||||
sender.sendMessage(CommonCommandMessage.UNEXPECTED_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
int buildNumber = response.getAsInt();
|
||||
|
||||
if (buildNumber > Constants.BUILD_NUMBER) {
|
||||
sender.sendMessage(String.format(
|
||||
COLOR_CHAR + "7There is a newer version of Floodgate available!\n" +
|
||||
COLOR_CHAR + "7You are " + COLOR_CHAR + "e%s " + COLOR_CHAR + "7builds behind.\n" +
|
||||
COLOR_CHAR + "7Download the latest Floodgate version here: " + COLOR_CHAR + "b%s",
|
||||
buildNumber - Constants.BUILD_NUMBER, baseUrl
|
||||
));
|
||||
sender.sendMessage(
|
||||
Message.VERSION_OUTDATED,
|
||||
literal("count", buildNumber - Constants.BUILD_NUMBER),
|
||||
literal("url", baseUrl));
|
||||
return;
|
||||
}
|
||||
if (buildNumber == Constants.BUILD_NUMBER) {
|
||||
sender.sendMessage(COLOR_CHAR + "aYou're running the latest version of Floodgate!");
|
||||
sender.sendMessage(Message.VERSION_LATEST);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
package org.geysermc.floodgate.core.connection;
|
||||
|
||||
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.Collection;
|
||||
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.Nullable;
|
||||
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 {
|
||||
private final Set<Connection> connections = Collections.synchronizedSet(new HashSet<>());
|
||||
@@ -93,9 +96,9 @@ public abstract class ConnectionManager {
|
||||
pendingConnections.add(connection);
|
||||
|
||||
logger.translatedInfo(
|
||||
"floodgate.ingame.login_name",
|
||||
connection.javaUsername(), connection.javaUuid()
|
||||
);
|
||||
CommonPlatformMessages.CONNECTION_LOGIN,
|
||||
literal("target", connection.javaUsername()),
|
||||
literal("target_uuid", connection.javaUuid()));
|
||||
}
|
||||
|
||||
public boolean addAcceptedConnection(Connection connection) {
|
||||
@@ -134,7 +137,9 @@ public abstract class ConnectionManager {
|
||||
pendingConnections.remove(connection);
|
||||
uuidToConnection.remove(connection.javaUuid(), 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() {
|
||||
|
||||
@@ -25,21 +25,25 @@
|
||||
|
||||
package org.geysermc.floodgate.core.connection;
|
||||
|
||||
import static org.geysermc.floodgate.core.platform.command.Placeholder.literal;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
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.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.crypto.FloodgateDataCodec;
|
||||
import org.geysermc.floodgate.core.crypto.exception.UnsupportedVersionException;
|
||||
import org.geysermc.floodgate.core.event.ConnectionJoinEvent;
|
||||
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.InvalidFormatException;
|
||||
import org.geysermc.floodgate.core.util.LanguageManager;
|
||||
@@ -93,11 +97,11 @@ public final class FloodgateDataHandler {
|
||||
private JoinResult canJoin(FloodgateConnection connection) {
|
||||
String disconnectReason = null;
|
||||
if (config.playerLink().requireLink() && !connection.isLinked()) {
|
||||
disconnectReason = languageManager.getString(
|
||||
"floodgate.core.not_linked",
|
||||
connection.languageCode(),
|
||||
Constants.LINK_INFO_URL
|
||||
);
|
||||
disconnectReason = MiniMessage.miniMessage().serialize(
|
||||
CommonPlatformMessages.NOT_LINKED.translateMessage(
|
||||
languageManager,
|
||||
connection.languageCode(),
|
||||
literal("url", Constants.LINK_INFO_URL)));
|
||||
}
|
||||
|
||||
var event = new ConnectionJoinEvent(connection, disconnectReason);
|
||||
|
||||
@@ -29,9 +29,13 @@ import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
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.util.MiniMessageUtils;
|
||||
|
||||
@Getter @Accessors(fluent = true)
|
||||
public class UserAudience {
|
||||
@@ -58,23 +62,30 @@ public class UserAudience {
|
||||
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);
|
||||
}
|
||||
|
||||
public void sendMessage(TranslatableMessage message, Object... args) {
|
||||
sendMessage(translateMessage(message, args));
|
||||
public void sendMessage(TranslatableMessage message, Placeholder... placeholders) {
|
||||
sendMessage(translateMessage(message, placeholders));
|
||||
}
|
||||
|
||||
public void disconnect(@NonNull String reason) {
|
||||
public void disconnect(Component reason) {
|
||||
commandUtil.kickPlayer(source(), reason);
|
||||
}
|
||||
|
||||
public void disconnect(TranslatableMessage message, Object... args) {
|
||||
public void disconnect(TranslatableMessage message, Placeholder... 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,11 +32,11 @@ import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.api.GeyserApiBase;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
import org.geysermc.floodgate.core.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.database.entity.LinkRequest;
|
||||
import org.geysermc.floodgate.core.database.entity.LinkedPlayer;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
|
||||
public abstract class CommonPlayerLink {
|
||||
@Getter private boolean enabled;
|
||||
|
||||
@@ -25,24 +25,34 @@
|
||||
|
||||
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.platform.command.Placeholder;
|
||||
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
|
||||
|
||||
public class LinkVerificationException extends RuntimeException {
|
||||
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 =
|
||||
new LinkVerificationException(Message.INVALID_CODE);
|
||||
new LinkVerificationException(Message.INVALID_CODE, literal("command", "/linkaccount"));
|
||||
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);
|
||||
this.message = message;
|
||||
this.placeholders = placeholders;
|
||||
}
|
||||
|
||||
public Message message() {
|
||||
public TranslatableMessage message() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public Placeholder[] placeholders() {
|
||||
return placeholders;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ import io.micronaut.runtime.event.annotation.EventListener;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.util.Set;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.event.lifecycle.PostEnableEvent;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.platform.listener.ListenerRegistration;
|
||||
|
||||
@Singleton
|
||||
|
||||
@@ -23,7 +23,11 @@
|
||||
* @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 {
|
||||
String LOGGER_NAME = "Floodgate";
|
||||
@@ -61,7 +65,9 @@ public interface FloodgateLogger {
|
||||
*/
|
||||
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.
|
||||
@@ -25,15 +25,17 @@
|
||||
|
||||
package org.geysermc.floodgate.core.logger;
|
||||
|
||||
import static org.geysermc.floodgate.core.util.MessageFormatter.format;
|
||||
|
||||
import io.micronaut.context.BeanProvider;
|
||||
import jakarta.inject.Inject;
|
||||
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.platform.command.Placeholder;
|
||||
import org.geysermc.floodgate.core.platform.command.TranslatableMessage;
|
||||
import org.geysermc.floodgate.core.util.LanguageManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
@Singleton
|
||||
public final class Slf4jFloodgateLogger implements FloodgateLogger {
|
||||
@@ -54,7 +56,7 @@ public final class Slf4jFloodgateLogger implements FloodgateLogger {
|
||||
|
||||
@Override
|
||||
public void error(String message, Throwable throwable, Object... args) {
|
||||
logger.error(format(message, args), throwable);
|
||||
logger.error(MessageFormatter.basicArrayFormat(message, args), throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,8 +70,16 @@ public final class Slf4jFloodgateLogger implements FloodgateLogger {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translatedInfo(String message, Object... args) {
|
||||
logger.info(languageManager.get().getLogString(message, args));
|
||||
public void info(Component message) {
|
||||
//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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.api.GeyserApiBase;
|
||||
@@ -161,20 +162,24 @@ public abstract class CommandUtil {
|
||||
* @param target the player that should receive 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.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
public LanguageManager languageManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whitelist the given Bedrock player.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -25,13 +25,13 @@
|
||||
|
||||
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 jakarta.annotation.PostConstruct;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.Locale;
|
||||
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.connection.audience.UserAudience;
|
||||
import org.incendo.cloud.Command;
|
||||
@@ -68,19 +68,21 @@ public abstract class SubCommands implements FloodgateCommand {
|
||||
}
|
||||
|
||||
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) {
|
||||
var permission = subCommand.permission();
|
||||
if (permission == null || context.sender().hasPermission(permission.get())) {
|
||||
helpMessage.append('\n').append(COLOR_CHAR).append('b')
|
||||
.append(subCommand.name().toLowerCase(Locale.ROOT))
|
||||
.append(COLOR_CHAR).append("f - ").append(COLOR_CHAR).append('7')
|
||||
.append(subCommand.description());
|
||||
var component = Component.newline()
|
||||
.append(Component.text(subCommand.name(), NamedTextColor.AQUA))
|
||||
.append(Component.text(" - "))
|
||||
.append(Component.text(subCommand.description(), NamedTextColor.GRAY));
|
||||
helpMessage = helpMessage.append(component);
|
||||
}
|
||||
}
|
||||
|
||||
context.sender().sendMessage(helpMessage.toString());
|
||||
context.sender().sendMessage(helpMessage);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
|
||||
@@ -25,36 +25,49 @@
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* TranslatableMessage is the interface for a message that can be translated. Messages are generally
|
||||
* implemented using enums.
|
||||
* TranslatableMessage is the common class for a message that can be translated
|
||||
*/
|
||||
public interface TranslatableMessage {
|
||||
/**
|
||||
* Returns the message attached to the enum identifier
|
||||
*/
|
||||
String getRawMessage();
|
||||
public class TranslatableMessage {
|
||||
private final String rawMessage;
|
||||
private final String[] translateParts;
|
||||
private final MessageType type;
|
||||
|
||||
/**
|
||||
* Returns the parts of this message (getRawMessage() split on " ")
|
||||
*/
|
||||
String[] getTranslateParts();
|
||||
public TranslatableMessage(String rawMessage, MessageType type) {
|
||||
this.rawMessage = rawMessage;
|
||||
this.translateParts = rawMessage.split(" ");
|
||||
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) {
|
||||
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++) {
|
||||
builder.append(manager.getString(translateParts[i], locale, args));
|
||||
if (translateParts.length != i + 1) {
|
||||
builder.append(' ');
|
||||
if (i != 0) {
|
||||
complete = complete.append(Component.text(' '));
|
||||
}
|
||||
complete = complete.append(manager.getString(translateParts[i], locale, type, placeholders));
|
||||
}
|
||||
return builder.toString();
|
||||
return complete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return rawMessage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.geysermc.cumulus.form.Form;
|
||||
import org.geysermc.cumulus.form.impl.FormDefinition;
|
||||
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.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils;
|
||||
import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel;
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ package org.geysermc.floodgate.core.util;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.net.URL;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
@@ -36,8 +35,15 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
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.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.platform.command.MessageType;
|
||||
import org.geysermc.floodgate.core.platform.command.Placeholder;
|
||||
|
||||
/**
|
||||
* Manages translations for strings in Floodgate
|
||||
@@ -124,46 +130,38 @@ public final class LanguageManager {
|
||||
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
|
||||
*
|
||||
* @param key language string to translate
|
||||
* @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
|
||||
*/
|
||||
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);
|
||||
String formatString = null;
|
||||
String translated = null;
|
||||
|
||||
if (properties != null) {
|
||||
formatString = properties.getProperty(key);
|
||||
translated = properties.getProperty(key);
|
||||
}
|
||||
|
||||
// try and get the key from the default locale
|
||||
if (formatString == null) {
|
||||
if (translated == null) {
|
||||
properties = localeMappings.get(defaultLocale);
|
||||
formatString = properties.getProperty(key);
|
||||
translated = properties.getProperty(key);
|
||||
}
|
||||
|
||||
// key wasn't found
|
||||
if (formatString == null) {
|
||||
return formatNotFound(key, values);
|
||||
}
|
||||
|
||||
//todo don't use color codes in the strings
|
||||
return MessageFormat.format(formatString.replace("'", "''").replace("&", "\u00a7"), values);
|
||||
return translated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,8 +185,16 @@ public final class LanguageManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
private String formatNotFound(String key, Object... rawArgs) {
|
||||
var args = Arrays.stream(rawArgs).map(Object::toString).collect(Collectors.joining(", "));
|
||||
return key + " " + args;
|
||||
private String formatNotFound(String key, Placeholder... placeholders) {
|
||||
return key + ' ' + Arrays.stream(placeholders)
|
||||
.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(", "));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -41,10 +41,10 @@ import org.bstats.charts.SimplePie;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.bstats.json.JsonObjectBuilder;
|
||||
import org.geysermc.api.GeyserApiBase;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.config.FloodgateConfig.MetricsConfig;
|
||||
import org.geysermc.floodgate.core.event.lifecycle.ShutdownEvent;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.platform.util.PlatformUtils;
|
||||
|
||||
@Singleton
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -34,9 +34,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.event.lifecycle.PostEnableEvent;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
|
||||
@Singleton
|
||||
public final class PostEnableMessages {
|
||||
@@ -57,12 +57,13 @@ public final class PostEnableMessages {
|
||||
}
|
||||
builder.append("**********************************");
|
||||
|
||||
messages.add(MessageFormatter.format(builder.toString(), args));
|
||||
messages.add(String.format(builder.toString(), args));
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
void registerPrefixMessages() {
|
||||
String prefix = config.rawUsernamePrefix();
|
||||
//todo these messages should also be translated
|
||||
|
||||
if (prefix.isEmpty()) {
|
||||
add(new String[]{
|
||||
@@ -72,21 +73,21 @@ public final class PostEnableMessages {
|
||||
});
|
||||
} else if (!Utils.isUniquePrefix(prefix)) {
|
||||
add(new String[]{
|
||||
"The prefix you entered in your Floodgate config ({}) 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!",
|
||||
"The prefix you entered in your Floodgate config (%s) could lead to username conflicts!",
|
||||
"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 *"
|
||||
}, prefix, prefix, prefix, prefix);
|
||||
}, prefix, prefix, prefix);
|
||||
}
|
||||
|
||||
if (prefix.length() >= 16) {
|
||||
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 (.)"
|
||||
}, prefix);
|
||||
} else if (prefix.length() > 2) {
|
||||
// we only have to warn them if we haven't replaced the prefix
|
||||
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.",
|
||||
"We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *"
|
||||
}, prefix, prefix.length());
|
||||
|
||||
Submodule core/src/main/resources/languages updated: 204f4fe492...35823c28bb
@@ -34,8 +34,7 @@ public final class Constants {
|
||||
|
||||
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 PRINT_ALL_PACKETS = false;
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ fastutil = "8.5.3"
|
||||
cloud = "2.0.0-beta.2"
|
||||
snakeyaml = "2.0"
|
||||
bstats = "3.0.2"
|
||||
adventure = "4.16.0"
|
||||
adventure-platform = "4.3.2"
|
||||
|
||||
# bungee
|
||||
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" }
|
||||
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-java = { module = "io.micronaut:micronaut-inject-java" }
|
||||
micronaut-context = { module = "io.micronaut:micronaut-context" }
|
||||
|
||||
@@ -5,6 +5,7 @@ dependencies {
|
||||
compileOnlyApi(projects.isolation)
|
||||
|
||||
implementation(libs.cloud.paper)
|
||||
implementation(libs.adventure.platform.bukkit)
|
||||
|
||||
compileOnlyApi(libs.paper.api)
|
||||
}
|
||||
|
||||
@@ -32,10 +32,10 @@ import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
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.connection.DataSeeker;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
|
||||
@Singleton
|
||||
public final class SpigotDataAddon implements InjectorAddon {
|
||||
|
||||
@@ -34,13 +34,13 @@ import io.netty.util.AttributeKey;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.InetSocketAddress;
|
||||
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.PacketBlocker;
|
||||
import org.geysermc.floodgate.core.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.DataSeeker;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
|
||||
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.ProxyUtils;
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
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.spigot.util.ClassNames;
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.api.SimpleFloodgateApi;
|
||||
import org.geysermc.floodgate.core.connection.ConnectionManager;
|
||||
import org.geysermc.floodgate.core.listener.McListener;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.util.LanguageManager;
|
||||
|
||||
@Singleton
|
||||
|
||||
@@ -29,7 +29,8 @@ import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.util.Collection;
|
||||
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.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -114,15 +115,18 @@ public final class SpigotCommandUtil extends CommandUtil {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Object target, String message) {
|
||||
public void sendMessage(Object target, Component message) {
|
||||
((CommandSender) target).sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kickPlayer(Object player, String message) {
|
||||
public void kickPlayer(Object target, Component message) {
|
||||
// can also be console
|
||||
if (player instanceof Player) {
|
||||
versionSpecificMethods.schedule(() -> ((Player) player).kickPlayer(message), 0);
|
||||
if (target instanceof Player player) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.UUID;
|
||||
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||
import org.geysermc.floodgate.api.handshake.HandshakeHandler;
|
||||
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;
|
||||
|
||||
@Singleton
|
||||
|
||||
@@ -32,11 +32,11 @@ import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
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.config.ProxyFloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.DataSeeker;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
|
||||
@Singleton
|
||||
public final class VelocityDataAddon implements InjectorAddon {
|
||||
|
||||
@@ -40,13 +40,13 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
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.PacketBlocker;
|
||||
import org.geysermc.floodgate.core.config.FloodgateConfig;
|
||||
import org.geysermc.floodgate.core.connection.DataSeeker;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateDataHandler;
|
||||
import org.geysermc.floodgate.core.connection.FloodgateDataHandler.HandleResult;
|
||||
import org.geysermc.floodgate.core.logger.FloodgateLogger;
|
||||
|
||||
public final class VelocityProxyDataHandler extends CommonNettyDataHandler {
|
||||
private static final Field HANDSHAKE;
|
||||
|
||||
@@ -41,10 +41,10 @@ import jakarta.inject.Singleton;
|
||||
import java.util.Collections;
|
||||
import net.kyori.adventure.text.Component;
|
||||
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.config.ProxyFloodgateConfig;
|
||||
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.velocity.player.VelocityConnectionManager;
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.util.UUID;
|
||||
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.logger.FloodgateLogger;
|
||||
import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils;
|
||||
import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel;
|
||||
import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel.Identity;
|
||||
|
||||
@@ -109,14 +109,14 @@ public final class VelocityCommandUtil extends CommandUtil {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Object target, String message) {
|
||||
((CommandSource) target).sendMessage(Component.text(message));
|
||||
public void sendMessage(Object target, Component message) {
|
||||
((CommandSource) target).sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kickPlayer(Object player, String message) {
|
||||
public void kickPlayer(Object player, Component message) {
|
||||
if (player instanceof Player) {
|
||||
((Player) player).disconnect(Component.text(message));
|
||||
((Player) player).disconnect(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user