From 486f1dc150dc1828dfb3d98231a207e4a8db4396 Mon Sep 17 00:00:00 2001 From: YuKun Liu Date: Sat, 27 Dec 2025 11:39:20 +0800 Subject: [PATCH] feat: code --- .../online/mineroo/common/BindRequest.java | 4 +- .../online/mineroo/common/MessageManager.java | 8 +- .../mineroo/paper/commands/BindCommand.java | 129 +++++++++++++----- .../paper/listeners/PlayerBindListener.java | 86 +++++++----- .../main/resources/i18n/messages.properties | 7 + 5 files changed, 160 insertions(+), 74 deletions(-) diff --git a/common/src/main/java/online/mineroo/common/BindRequest.java b/common/src/main/java/online/mineroo/common/BindRequest.java index a03b943..781ae88 100644 --- a/common/src/main/java/online/mineroo/common/BindRequest.java +++ b/common/src/main/java/online/mineroo/common/BindRequest.java @@ -282,7 +282,9 @@ public class BindRequest { Map params = new HashMap<>(); - params.put("web_email", userEmail); + if (userEmail != null) { + params.put("web_email", userEmail); + } if (playerUuid != null) { String simpleUuid = playerUuid.toString().replace("-", ""); diff --git a/common/src/main/java/online/mineroo/common/MessageManager.java b/common/src/main/java/online/mineroo/common/MessageManager.java index 9607df9..359fd37 100644 --- a/common/src/main/java/online/mineroo/common/MessageManager.java +++ b/common/src/main/java/online/mineroo/common/MessageManager.java @@ -1,15 +1,13 @@ package online.mineroo.common; +import java.util.Locale; +import java.util.ResourceBundle; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import java.util.Locale; -import java.util.ResourceBundle; - public class MessageManager { - private ResourceBundle bundle; private final MiniMessage miniMessage; @@ -54,7 +52,7 @@ public class MessageManager { return miniMessage.deserialize(raw, builder.build()); } - private String getString(String key) { + public String getString(String key) { try { return bundle.getString(key); } catch (Exception e) { diff --git a/paper/src/main/java/online/mineroo/paper/commands/BindCommand.java b/paper/src/main/java/online/mineroo/paper/commands/BindCommand.java index a98e655..7451d7a 100644 --- a/paper/src/main/java/online/mineroo/paper/commands/BindCommand.java +++ b/paper/src/main/java/online/mineroo/paper/commands/BindCommand.java @@ -5,17 +5,22 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.tree.LiteralCommandNode; - import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; +import io.papermc.paper.dialog.Dialog; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import java.util.UUID; +import net.kyori.adventure.key.Key; import online.mineroo.common.BindRequest; +import online.mineroo.common.BindRequest.PlayerBindStatusEnum; +import online.mineroo.common.MessageManager; import online.mineroo.paper.MinerooCore; import online.mineroo.paper.ProxyNetworkService; - +import org.bukkit.entity.Player; import org.slf4j.Logger; public class BindCommand { - private MinerooCore plugin; public BindCommand(MinerooCore plugin) { @@ -23,28 +28,61 @@ public class BindCommand { } public LiteralCommandNode build() { - LiteralArgumentBuilder bind = Commands.literal("bind") - .executes(context -> { - CommandSourceStack sender = context.getSource(); - if (!sender.getSender().hasPermission("mineroo.admin.bind.server")) { - return bindPlayer(context); - } - return 0; - }); + LiteralArgumentBuilder bind = Commands.literal("bind").executes(context -> { + CommandSourceStack sender = context.getSource(); + if (!sender.getSender().hasPermission("mineroo.admin.bind.server")) { + return bindPlayer(context); + } + return 0; + }); - bind.then( - Commands.literal("server") - .requires(sender -> sender.getSender().hasPermission("mineroo.admin.bind.server")) - .executes(this::bindServer)); + bind.then(Commands.literal("server") + .requires(sender -> sender.getSender().hasPermission("mineroo.admin.bind.server")) + .executes(this::bindServer)); - bind.then( - Commands.literal("player").requires(sender -> sender.getSender().hasPermission("mineroo.admin.bind.server")) - .executes(this::bindPlayer)); + bind.then(Commands.literal("player") + .requires(sender -> sender.getSender().hasPermission("mineroo.admin.bind.server")) + .executes(this::bindPlayer)); return bind.build(); } private int bindPlayer(CommandContext context) { + Logger logger = this.plugin.getSLF4JLogger(); + MessageManager messageManager = this.plugin.getMessageManager(); + + if (context.getSource().getExecutor() instanceof Player player) { + UUID uuid = player.getUniqueId(); + + if (uuid == null) { + return Command.SINGLE_SUCCESS; + } + + try { + this.plugin.getBindRequest().checkPlayerBindStatus(uuid, null).thenAccept(response -> { + PlayerBindStatusEnum status = response.getStatus(); + + plugin.getSLF4JLogger().debug(status.toString()); + + if (status == PlayerBindStatusEnum.BOUND) { + player.sendMessage(messageManager.get("info.bind.player.already-bound")); + } else if (status == PlayerBindStatusEnum.NOT_BOUND) { + Dialog dialog = RegistryAccess.registryAccess() + .getRegistry(RegistryKey.DIALOG) + .get(Key.key("mineroo:bind_user")); + if (dialog == null) { + logger.error("load user bind dialog failed."); + player.sendMessage(messageManager.get("info.bind.player.dialog-undefined")); + } + + // TODO: Need a timeout check + player.showDialog(dialog); + } + }); + + } finally { + } + } return Command.SINGLE_SUCCESS; } @@ -58,13 +96,16 @@ public class BindCommand { private void sendMotdTokenToVelocity(String motdToken) { // Send via any online player (Plugin Messaging must be attached to a player) - org.bukkit.entity.Player player = org.bukkit.Bukkit.getOnlinePlayers().stream().findFirst().orElse(null); + org.bukkit.entity.Player player = + org.bukkit.Bukkit.getOnlinePlayers().stream().findFirst().orElse(null); if (player == null) return; com.google.common.io.ByteArrayDataOutput out = com.google.common.io.ByteStreams.newDataOutput(); out.writeUTF(online.mineroo.common.ProtocolConstants.BIND_MOTD_TOKEN); out.writeUTF(motdToken); - player.sendPluginMessage(plugin, online.mineroo.common.ProtocolConstants.PROTOCOL_CHANNEL, out.toByteArray()); + player.sendPluginMessage( + plugin, online.mineroo.common.ProtocolConstants.PROTOCOL_CHANNEL, out.toByteArray() + ); } private int bindServer(CommandContext context) throws CommandSyntaxException { @@ -73,9 +114,9 @@ public class BindCommand { Logger logger = plugin.getSLF4JLogger(); BindRequest bindRequest = plugin.getBindRequest(); try { - String address = plugin.getConfigObject().getServer().getServerBind().getAddress(); - String port = String.valueOf(plugin.getConfigObject().getServer().getServerBind().getPort()); + String port = + String.valueOf(plugin.getConfigObject().getServer().getServerBind().getPort()); if (plugin.getNetworkService() instanceof ProxyNetworkService) { address = "$hostname"; port = "$port"; @@ -84,8 +125,9 @@ public class BindCommand { // 1. Check binding status if (bindRequest.checkBindStatus(address, port).join()) { plugin.getMessageManager().get("command.bind.server.already-bound"); - context.getSource().getSender() - .sendMessage(plugin.getMessageManager().get("command.bind.server.already-bound")); + context.getSource().getSender().sendMessage( + plugin.getMessageManager().get("command.bind.server.already-bound") + ); return; } // 2. Initiate MOTD verification @@ -94,7 +136,9 @@ public class BindCommand { String motdToken = bindRequest.getMotdToken(); // Send MOTD token to Velocity applyMotdToken(motdToken); - context.getSource().getSender().sendMessage(plugin.getMessageManager().get("command.bind.server.wait")); + context.getSource().getSender().sendMessage( + plugin.getMessageManager().get("command.bind.server.wait") + ); try { Thread.sleep(2 * 60 * 1000 + 5000); // 2m 5s } catch (InterruptedException e) { @@ -105,16 +149,23 @@ public class BindCommand { boolean success = false; int maxRetries = 3; for (int i = 1; i <= maxRetries; i++) { - if (bindRequest.finalizeServerBinding( - plugin.getConfigObject().getServer().getServerName(), - plugin.getConfigObject().getServer().getDescription()).join()) { + if (bindRequest + .finalizeServerBinding( + plugin.getConfigObject().getServer().getServerName(), + plugin.getConfigObject().getServer().getDescription() + ) + .join()) { success = true; break; } if (i < maxRetries) { - context.getSource().getSender().sendMessage( - plugin.getMessageManager().get("command.bind.server.retry", "current", String.valueOf(i), "max", - String.valueOf(maxRetries))); + context.getSource().getSender().sendMessage(plugin.getMessageManager().get( + "command.bind.server.retry", + "current", + String.valueOf(i), + "max", + String.valueOf(maxRetries) + )); try { Thread.sleep(10000); } catch (InterruptedException e) { @@ -123,18 +174,24 @@ public class BindCommand { } } if (success) { - context.getSource().getSender().sendMessage(plugin.getMessageManager().get("command.bind.server.success")); + context.getSource().getSender().sendMessage( + plugin.getMessageManager().get("command.bind.server.success") + ); } else { - context.getSource().getSender().sendMessage(plugin.getMessageManager().get("command.bind.server.failed")); + context.getSource().getSender().sendMessage( + plugin.getMessageManager().get("command.bind.server.failed") + ); } } else { - context.getSource().getSender() - .sendMessage(plugin.getMessageManager().get("command.bind.server.inital.failed")); + context.getSource().getSender().sendMessage( + plugin.getMessageManager().get("command.bind.server.inital.failed") + ); } } catch (Exception ex) { logger.error("Bind process error", ex); context.getSource().getSender().sendMessage( - plugin.getMessageManager().get("command.bind.server.failed")); + plugin.getMessageManager().get("command.bind.server.failed") + ); } finally { // After binding is complete, you can send a message to clear the MOTD token applyMotdToken(""); // Clear MOTD diff --git a/paper/src/main/java/online/mineroo/paper/listeners/PlayerBindListener.java b/paper/src/main/java/online/mineroo/paper/listeners/PlayerBindListener.java index 7343077..00e5f6c 100644 --- a/paper/src/main/java/online/mineroo/paper/listeners/PlayerBindListener.java +++ b/paper/src/main/java/online/mineroo/paper/listeners/PlayerBindListener.java @@ -3,6 +3,7 @@ package online.mineroo.paper.listeners; import com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent; import io.papermc.paper.connection.PlayerConfigurationConnection; +import io.papermc.paper.connection.PlayerGameConnection; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.dialog.DialogResponseView; import io.papermc.paper.event.connection.configuration.AsyncPlayerConnectionConfigureEvent; @@ -14,6 +15,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; @@ -24,10 +26,10 @@ import online.mineroo.common.BindRequest.PlayerBindResponse; import online.mineroo.common.BindRequest.PlayerBindStatusEnum; import online.mineroo.paper.Config; import online.mineroo.paper.MinerooCore; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.jspecify.annotations.NullMarked; -import org.slf4j.Logger; @NullMarked public class PlayerBindListener implements Listener { @@ -98,7 +100,7 @@ public class PlayerBindListener implements Listener { } else if (bindResponse.getStatus() == PlayerBindEnum.PENDING) { audience.closeDialog(); String msg = "Binding request submitted!\nPlease go to Mineroo.Online to confirm the " - + "binding. After confirmation, please re-enter the server."; + + "binding. After confirmation, please re-enter the server."; connection.disconnect(Component.text(msg, NamedTextColor.GREEN)); } else { audience.closeDialog(); @@ -134,17 +136,40 @@ public class PlayerBindListener implements Listener { @EventHandler void onHandleDialog(PlayerCustomClickEvent event) { - Logger logger = plugin.getSLF4JLogger(); - - // Handle custom click only for configuration connection. - if (!(event.getCommonConnection() - instanceof PlayerConfigurationConnection configurationConnection)) { - return; + // Main handlr only use for PlayerConfigureationConnection, + // Inside Block use for handle command bind request. + if (event.getCommonConnection() instanceof PlayerGameConnection playerConn) { + // handle command bind + Player player = playerConn.getPlayer(); + UUID playerUuid = player.getUniqueId(); + this.PlayerBindProcess(event, playerUuid, response -> { + if (response.getStatus() == PlayerBindEnum.PENDING) { + player.sendMessage(this.plugin.getMessageManager().get("info.bind.player.pending")); + } else if (response.getStatus() == PlayerBindEnum.BOUND) { + player.sendMessage(this.plugin.getMessageManager().get("info.bind.player.success")); + } else { + String statusText = + (response.getStatus() != null) ? response.getStatus().toString() : "UNKNOWN_STATUS"; + String messageText = + (response.getMessage() != null) ? response.getMessage() : "Bind Failed"; + String fullMessage = "[ " + statusText + " ]: " + messageText; + player.sendMessage(Component.text(fullMessage, NamedTextColor.RED)); + } + }); + } else if (event.getCommonConnection() + instanceof PlayerConfigurationConnection configurationConnection) { + // handle required configuration event bind + UUID playerUuid = configurationConnection.getProfile().getId(); + this.PlayerBindProcess(event, playerUuid, response -> { + setConnectionJoinResult(playerUuid, response); + }); } + } - UUID uniqueId = configurationConnection.getProfile().getId(); - - if (uniqueId == null) { + private void PlayerBindProcess( + PlayerCustomClickEvent event, UUID playerUuid, Consumer callback + ) { + if (playerUuid == null) { return; } @@ -157,32 +182,29 @@ public class PlayerBindListener implements Listener { } String userEmail = view.getText("user_email"); + String playerName = "Unknown"; if (event.getCommonConnection() instanceof PlayerConfigurationConnection conn) { - BindRequest bindRequest = plugin.getBindRequest(); - String playerName = conn.getProfile().getName(); - - bindRequest.PlayerBindRequest(userEmail, uniqueId, conn.getProfile().getName()) - .thenAccept(response -> { setConnectionJoinResult(uniqueId, response); }) - .exceptionally(ex -> { - logger.error("Error occurred during bind request for " + playerName, ex); - setConnectionJoinResult( - uniqueId, - BindRequest.createPlayerBindErrorResponse( - "Network request failed, please contact the server administrator." - ) - ); - return null; - }); - ; + playerName = conn.getProfile().getName(); + } else if (event.getCommonConnection() instanceof PlayerGameConnection conn) { + playerName = conn.getPlayer().getName(); } - } else if (key.equals(Key.key("mineroo:bind_user/cancel"))) { - // If it is the same as the agree one, set the result to true. + BindRequest bindRequest = plugin.getBindRequest(); - setConnectionJoinResult( - uniqueId, BindRequest.createPlayerBindErrorResponse("Canceled the bind requirement") - ); + bindRequest.PlayerBindRequest(userEmail, playerUuid, playerName) + .thenAccept(response -> { callback.accept(response); }) + .exceptionally(ex -> { + callback.accept(BindRequest.createPlayerBindErrorResponse( + "Network request failed: " + ex.getMessage() + )); + return null; + }); + + } else if (key.equals(Key.key("mineroo:bind_user/cancel"))) { + callback.accept(BindRequest.createPlayerBindErrorResponse( + this.plugin.getMessageManager().getString("info.bind.player.canceled") + )); } } diff --git a/paper/src/main/resources/i18n/messages.properties b/paper/src/main/resources/i18n/messages.properties index 07c6ca0..2963ec8 100644 --- a/paper/src/main/resources/i18n/messages.properties +++ b/paper/src/main/resources/i18n/messages.properties @@ -15,6 +15,13 @@ command.bind.server.success=绑定成功! command.bind.server.failed=绑定失败。 command.bind.server.retry=验证未通过,10 秒后重试 (/) ... +## Player Bind [Both for screen and command] +info.bind.player.already-bound=当前用户已绑定 +info.bind.player.dialog-undefined=Dialog 加载失败,请联系管理员 +info.bind.player.pending = "绑定申请已发送,请登录 Mineroo 网站进行后续操作。" +info.bind.player.success = "绑定成功!" +info.bind.player.canceled = "绑定请求已取消。" + # Reload Command command.reload.success=配置文件重载成功!耗时 command.reload.failed=配置文件重载失败,请查看控制台日志。