feat: code
This commit is contained in:
@@ -2,7 +2,6 @@ package online.mineroo.common;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import online.mineroo.common.NetworkServiceInterface;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package online.mineroo.common;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ProxyNetworkRequest {
|
||||
private final String requestId;
|
||||
private final String method; // "GET" or "POST"
|
||||
private final String endpoint;
|
||||
private final Map<String, String> params;
|
||||
private final String jsonBody;
|
||||
|
||||
public ProxyNetworkRequest(String method, String endpoint, Map<String, String> params, JsonObject body) {
|
||||
this.requestId = UUID.randomUUID().toString();
|
||||
this.method = method;
|
||||
this.endpoint = endpoint;
|
||||
this.params = params;
|
||||
this.jsonBody = (body != null) ? body.toString() : null;
|
||||
}
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public String getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public Map<String, String> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public String getJsonBody() {
|
||||
return jsonBody;
|
||||
}
|
||||
}
|
||||
@@ -5,21 +5,39 @@ import org.bukkit.configuration.file.FileConfiguration;
|
||||
public class Config {
|
||||
|
||||
private final ServerSection server;
|
||||
private final PlayerSection player;
|
||||
private final PlayersSection player;
|
||||
private final ProxySection proxy;
|
||||
|
||||
public Config(FileConfiguration config) {
|
||||
this.proxy = new ProxySection(config);
|
||||
this.server = new ServerSection(config);
|
||||
this.player = new PlayerSection(config);
|
||||
this.player = new PlayersSection(config);
|
||||
}
|
||||
|
||||
public ProxySection getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
public ServerSection getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public PlayerSection getPlayer() {
|
||||
public PlayersSection getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public static class ProxySection {
|
||||
private final boolean useVelocity;
|
||||
|
||||
public ProxySection(FileConfiguration config) {
|
||||
this.useVelocity = config.getBoolean("proxy.use_velocity", false);
|
||||
}
|
||||
|
||||
public boolean isUseVelocity() {
|
||||
return useVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServerSection {
|
||||
private final String serverName;
|
||||
private final String description;
|
||||
@@ -71,13 +89,13 @@ public class Config {
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerSection {
|
||||
public static class PlayersSection {
|
||||
private final PlayerBindSection bind;
|
||||
|
||||
public PlayerSection(FileConfiguration config) {
|
||||
public PlayersSection(FileConfiguration config) {
|
||||
this.bind = new PlayerBindSection(
|
||||
config.getBoolean("player.bind.required", false),
|
||||
config.getBoolean("player.bind.share_player_info", true));
|
||||
config.getBoolean("players.bind.required", false),
|
||||
config.getBoolean("players.bind.share_player_info", true));
|
||||
}
|
||||
|
||||
public PlayerBindSection getPlayerBind() {
|
||||
|
||||
@@ -2,7 +2,11 @@ package online.mineroo.paper;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
|
||||
import online.mineroo.common.HttpNetworkService;
|
||||
import online.mineroo.common.MessageManager;
|
||||
import online.mineroo.common.NetworkServiceInterface;
|
||||
import online.mineroo.paper.commands.MainCommand;
|
||||
import online.mineroo.paper.utils.PlayerBindDialog;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -13,12 +17,20 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
||||
public class MinerooCore extends JavaPlugin implements Listener {
|
||||
|
||||
private MessageManager messageManager;
|
||||
private NetworkServiceInterface networkService;
|
||||
private Config config;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
saveDefaultConfig();
|
||||
|
||||
reloadAll();
|
||||
|
||||
this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {
|
||||
commands.registrar().register(new MainCommand(this).build());
|
||||
});
|
||||
|
||||
messageManager = new MessageManager();
|
||||
|
||||
getServer().getPluginManager().registerEvents(this, this);
|
||||
@@ -38,4 +50,37 @@ public class MinerooCore extends JavaPlugin implements Listener {
|
||||
|
||||
player.sendMessage(messageManager.get("message.test", "player", player.getName()));
|
||||
}
|
||||
|
||||
public void reloadAll() {
|
||||
reloadConfig();
|
||||
this.config = new Config(getConfig());
|
||||
|
||||
boolean useVelocity = this.config.getProxy().isUseVelocity();
|
||||
if (useVelocity) {
|
||||
this.networkService = new ProxyNetworkService(this);
|
||||
getLogger().info("Using Velocity proxy network service.");
|
||||
} else {
|
||||
String token = config.getServer().getServerBind().getBindToken();
|
||||
this.networkService = new HttpNetworkService("https://oapi.mineroo.online", "mbind", token);
|
||||
getLogger().info("Using direct HTTP network service.");
|
||||
}
|
||||
|
||||
if (this.messageManager == null) {
|
||||
this.messageManager = new MessageManager();
|
||||
} else {
|
||||
this.messageManager.reload();
|
||||
}
|
||||
}
|
||||
|
||||
public Config getConfigObject() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public NetworkServiceInterface getNetworkService() {
|
||||
return networkService;
|
||||
}
|
||||
|
||||
public MessageManager getMessageManager() {
|
||||
return messageManager;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package online.mineroo.paper;
|
||||
|
||||
import com.google.common.io.ByteArrayDataInput;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import online.mineroo.common.ProxyNetworkRequest;
|
||||
import online.mineroo.common.NetworkServiceInterface;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ProxyNetworkService implements NetworkServiceInterface, PluginMessageListener {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final Gson gson = new Gson();
|
||||
private final String CHANNEL = "mineroo:net";
|
||||
|
||||
// Store pending requests <RequestId, Future>
|
||||
private final Map<String, CompletableFuture<String>> pendingRequests = new ConcurrentHashMap<>();
|
||||
|
||||
public ProxyNetworkService(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
// Register channels
|
||||
plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, CHANNEL);
|
||||
plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, CHANNEL, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> getData(String endpoint, Map<String, String> params) {
|
||||
return sendRequest("GET", endpoint, params, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> postData(String endpoint, JsonObject body) {
|
||||
return sendRequest("POST", endpoint, null, body);
|
||||
}
|
||||
|
||||
private CompletableFuture<String> sendRequest(String method, String endpoint, Map<String, String> params,
|
||||
JsonObject body) {
|
||||
CompletableFuture<String> future = new CompletableFuture<>();
|
||||
|
||||
// 1. Check if there is any player online (Plugin Message must be sent via a
|
||||
// player)
|
||||
Player player = com.google.common.collect.Iterables.getFirst(Bukkit.getOnlinePlayers(), null);
|
||||
if (player == null) {
|
||||
future.completeExceptionally(new IllegalStateException("No player online to proxy request to Velocity"));
|
||||
return future;
|
||||
}
|
||||
|
||||
// 2. Prepare the packet
|
||||
ProxyNetworkRequest req = new ProxyNetworkRequest(method, endpoint, params, body);
|
||||
pendingRequests.put(req.getRequestId(), future);
|
||||
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF("API_REQ"); // Sub-channel
|
||||
out.writeUTF(gson.toJson(req)); // Payload
|
||||
|
||||
// 3. Send
|
||||
player.sendPluginMessage(plugin, CHANNEL, out.toByteArray());
|
||||
|
||||
// 4. Set timeout (prevent memory leak if Velocity does not respond)
|
||||
plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, () -> {
|
||||
CompletableFuture<String> f = pendingRequests.remove(req.getRequestId());
|
||||
if (f != null) {
|
||||
f.completeExceptionally(new java.util.concurrent.TimeoutException("Proxy request timed out"));
|
||||
}
|
||||
}, 100L); // 5 seconds timeout
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
|
||||
if (!channel.equals(CHANNEL))
|
||||
return;
|
||||
|
||||
ByteArrayDataInput in = ByteStreams.newDataInput(message);
|
||||
String subChannel = in.readUTF();
|
||||
|
||||
if (subChannel.equals("API_RESP")) {
|
||||
String reqId = in.readUTF();
|
||||
boolean success = in.readBoolean();
|
||||
String data = in.readUTF(); // If success: body, if failure: error message
|
||||
|
||||
CompletableFuture<String> future = pendingRequests.remove(reqId);
|
||||
if (future != null) {
|
||||
if (success) {
|
||||
future.complete(data);
|
||||
} else {
|
||||
future.completeExceptionally(new RuntimeException(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package online.mineroo.paper.commands;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
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 online.mineroo.common.BindRequest;
|
||||
import online.mineroo.paper.MinerooCore;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BindCommand {
|
||||
|
||||
private MinerooCore plugin;
|
||||
|
||||
public BindCommand(MinerooCore plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public LiteralCommandNode<CommandSourceStack> build() {
|
||||
LiteralArgumentBuilder<CommandSourceStack> bind = Commands.literal("bind");
|
||||
|
||||
bind.then(
|
||||
Commands.literal("server")
|
||||
.requires(sender -> sender.getSender().hasPermission("mineroo.admin.bind.server")))
|
||||
.executes(this::bindServer);
|
||||
|
||||
bind.then(Commands.literal("player"));
|
||||
|
||||
return bind.build();
|
||||
}
|
||||
|
||||
private int bindServer(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
|
||||
// Use slf4j logger for BindRequest to keep log style consistent across
|
||||
// platforms
|
||||
Logger logger = LoggerFactory.getLogger("MinerooPaper");
|
||||
BindRequest bindRequest = new BindRequest(
|
||||
logger,
|
||||
plugin.getNetworkService());
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package online.mineroo.paper.commands;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
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 online.mineroo.paper.MinerooCore;
|
||||
import online.mineroo.common.MessageManager;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
public class MainCommand {
|
||||
|
||||
private final MinerooCore plugin;
|
||||
|
||||
public MainCommand(MinerooCore plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public LiteralCommandNode<CommandSourceStack> build() {
|
||||
LiteralArgumentBuilder<CommandSourceStack> root = Commands.literal("mineroo");
|
||||
|
||||
root.then(
|
||||
Commands.literal("reload")
|
||||
.requires(sender -> sender.getSender().hasPermission("mineroo.admin.reload"))
|
||||
.executes(this::executeReload));
|
||||
|
||||
root.then(new BindCommand(plugin).build());
|
||||
|
||||
return root.build();
|
||||
}
|
||||
|
||||
private int executeReload(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
|
||||
// Reload plugin config and message manager
|
||||
plugin.reloadConfig();
|
||||
plugin.reloadAll();
|
||||
|
||||
if (context.getSource().getExecutor() instanceof Player player) {
|
||||
player.updateCommands();
|
||||
}
|
||||
|
||||
MessageManager messageManager = plugin.getMessageManager();
|
||||
|
||||
messageManager.reload();
|
||||
|
||||
// Send feedback
|
||||
Component msg = messageManager.get("message.reload.success");
|
||||
context.getSource().getSender().sendMessage(msg);
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,19 @@
|
||||
proxy:
|
||||
use_velocity: false
|
||||
|
||||
server:
|
||||
# Only for bind commands
|
||||
# Only for `bind server` commands
|
||||
serverName: ""
|
||||
description: "A minecraft server"
|
||||
|
||||
# Only for bind commands
|
||||
# Only for `bind server` commands
|
||||
bind:
|
||||
address: ""
|
||||
port: 0
|
||||
token: "get token from `mineroo.online/resources/servers` page!"
|
||||
|
||||
player:
|
||||
players:
|
||||
# for player bind
|
||||
bind:
|
||||
# Only bound player can enter this server
|
||||
# > server will kick all mineroo unknown player
|
||||
|
||||
@@ -5,3 +5,5 @@ dialog.bind.player.confirm = <green>确认</green>
|
||||
dialog.bind.player.cancel = <red>取消</red>
|
||||
|
||||
message.bind.player.success = 请前往 Mineroo 个人中心完成验证。
|
||||
|
||||
message.reload.success = <green>插件配置文件重载成功!</green>
|
||||
|
||||
@@ -1,6 +1,27 @@
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/paper-plugin.json
|
||||
name: MinerooCore
|
||||
main: online.mineroo.paper.MinerooCore
|
||||
version: 1.0.0
|
||||
author: YuKun Liu
|
||||
website: https://mineroo.online
|
||||
description: Mineroo Base Plugin
|
||||
api-version: "1.21.10"
|
||||
permissions:
|
||||
mineroo.admin.reload:
|
||||
description: "Reload plugin config files."
|
||||
default: op
|
||||
|
||||
mineroo.admin.bind.server:
|
||||
description: Bind the server instance
|
||||
default: op
|
||||
|
||||
mineroo.user.bind.player:
|
||||
description: Bind user account
|
||||
default: "true"
|
||||
|
||||
mineroo.admin:
|
||||
description: Grant all administrative permissions
|
||||
default: op
|
||||
children:
|
||||
mineroo.admin.reload: true
|
||||
mineroo.admin.bind.server: true
|
||||
|
||||
Reference in New Issue
Block a user