feat: use clang-format
This commit is contained in:
@@ -66,7 +66,7 @@ public class Config {
|
||||
this.description = config.getString("server.description", "A minecraft server");
|
||||
this.bind = new ServerBindSection(
|
||||
config.getString("server.bind.address", ""),
|
||||
config.getInt("server.bind.port", 0),
|
||||
config.getObject("server.bind.port", Integer.class, null),
|
||||
config.getString("server.bind.token", "get token from `mineroo.online/resources/servers` page!"));
|
||||
}
|
||||
|
||||
@@ -85,10 +85,10 @@ public class Config {
|
||||
|
||||
public static class ServerBindSection {
|
||||
private final String address;
|
||||
private final int port;
|
||||
private final Integer port;
|
||||
private final String bindToken;
|
||||
|
||||
public ServerBindSection(String address, int port, String bindToken) {
|
||||
public ServerBindSection(String address, Integer port, String bindToken) {
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.bindToken = bindToken;
|
||||
@@ -98,7 +98,7 @@ public class Config {
|
||||
return address;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
package online.mineroo.paper;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
|
||||
import online.mineroo.common.BindRequest;
|
||||
import online.mineroo.common.HttpNetworkService;
|
||||
import online.mineroo.common.MessageManager;
|
||||
import online.mineroo.common.NetworkServiceInterface;
|
||||
import online.mineroo.common.ProtocolConstants;
|
||||
import online.mineroo.paper.commands.MainCommand;
|
||||
import online.mineroo.paper.utils.PlayerBindDialog;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import online.mineroo.paper.listeners.BindListener;
|
||||
import online.mineroo.paper.listeners.PlayerBindListener;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class MinerooCore extends JavaPlugin implements Listener {
|
||||
|
||||
private MessageManager messageManager;
|
||||
private NetworkServiceInterface networkService;
|
||||
private BindRequest bindRequest;
|
||||
private Config config;
|
||||
|
||||
private BindListener bindListener;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
saveDefaultConfig();
|
||||
|
||||
this.bindListener = new BindListener();
|
||||
getServer().getPluginManager().registerEvents(bindListener, this);
|
||||
|
||||
reloadAll();
|
||||
|
||||
this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {
|
||||
commands.registrar().register(new MainCommand(this).build());
|
||||
});
|
||||
|
||||
this.getServer().getMessenger().registerOutgoingPluginChannel(this, ProtocolConstants.PROTOCOL_CHANNEL);
|
||||
getServer().getPluginManager().registerEvents(new PlayerBindListener(this), this);
|
||||
|
||||
messageManager = new MessageManager();
|
||||
|
||||
@@ -40,19 +40,7 @@ public class MinerooCore extends JavaPlugin implements Listener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
PlayerBindDialog dialog = new PlayerBindDialog();
|
||||
|
||||
player.showDialog(dialog.getDialog(messageManager));
|
||||
|
||||
player.sendMessage(messageManager.get("message.test", "player", player.getName()));
|
||||
}
|
||||
public void onDisable() {}
|
||||
|
||||
public void reloadAll() {
|
||||
reloadConfig();
|
||||
@@ -66,10 +54,11 @@ public class MinerooCore extends JavaPlugin implements Listener {
|
||||
String token = config.getServer().getServerBind().getBindToken();
|
||||
String hostname = config.getTest().getApiHostname();
|
||||
this.networkService = new HttpNetworkService(hostname, "mserver", token);
|
||||
getLogger().info("Using direct HTTP network service.");
|
||||
getLogger().info("API: " + hostname);
|
||||
getLogger().info("Using direct HTTP network [ " + hostname + " ]");
|
||||
}
|
||||
|
||||
bindRequest = new BindRequest(this.getSLF4JLogger(), this.getNetworkService());
|
||||
|
||||
if (this.messageManager == null) {
|
||||
this.messageManager = new MessageManager();
|
||||
} else {
|
||||
@@ -88,4 +77,12 @@ public class MinerooCore extends JavaPlugin implements Listener {
|
||||
public MessageManager getMessageManager() {
|
||||
return messageManager;
|
||||
}
|
||||
|
||||
public BindListener getBindListener() {
|
||||
return this.bindListener;
|
||||
}
|
||||
|
||||
public BindRequest getBindRequest() {
|
||||
return bindRequest;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package online.mineroo.paper;
|
||||
|
||||
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
||||
import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
import io.papermc.paper.registry.data.dialog.DialogBase;
|
||||
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.input.DialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||
import io.papermc.paper.registry.event.RegistryEvents;
|
||||
import io.papermc.paper.registry.keys.DialogKeys;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import online.mineroo.common.MessageManager;
|
||||
|
||||
public class MinerooCoreBootstrap implements PluginBootstrap {
|
||||
@Override
|
||||
public void bootstrap(BootstrapContext context) {
|
||||
MessageManager messageManager = new MessageManager();
|
||||
|
||||
ActionButton confirmButton =
|
||||
ActionButton.create(messageManager.get("dialog.bind.player.confirm"), null, 100, null);
|
||||
|
||||
ActionButton cancelButton =
|
||||
ActionButton.create(messageManager.get("dialog.bind.player.cancel"), null, 100, null);
|
||||
|
||||
DialogInput usernameInput =
|
||||
DialogInput.text("username", messageManager.get("dialog.bind.player.email")).build();
|
||||
|
||||
DialogBase dialogBase =
|
||||
DialogBase.builder(messageManager.get("dialog.bind.player.title"))
|
||||
.body(
|
||||
List.of(DialogBody.plainMessage(messageManager.get("dialog.bind.player.content")))
|
||||
)
|
||||
.inputs(List.of(usernameInput))
|
||||
.build();
|
||||
|
||||
DialogType confirmationType = DialogType.confirmation(confirmButton, cancelButton);
|
||||
|
||||
context.getLifecycleManager().registerEventHandler(RegistryEvents.DIALOG.compose().newHandler(
|
||||
event
|
||||
-> event.registry().register(
|
||||
DialogKeys.create(Key.key("papermc:bind_mineroo_user")),
|
||||
builder -> builder.base(dialogBase).type(confirmationType)
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -5,33 +5,44 @@ 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.NetworkResponse;
|
||||
import online.mineroo.common.NetworkServiceInterface;
|
||||
import online.mineroo.common.ProtocolConstants;
|
||||
import online.mineroo.common.NetworkResponse;
|
||||
import online.mineroo.common.ProxyNetworkRequest;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class ProxyNetworkService implements NetworkServiceInterface, PluginMessageListener {
|
||||
public class ProxyNetworkService implements NetworkServiceInterface, PluginMessageListener, Listener {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final Gson gson = new Gson();
|
||||
private final String CHANNEL = "mineroo:net";
|
||||
private final String CHANNEL = ProtocolConstants.PROTOCOL_CHANNEL;
|
||||
|
||||
// Store pending requests <RequestId, Future>
|
||||
// Stores sent requests <RequestId, Future>
|
||||
private final Map<String, CompletableFuture<NetworkResponse>> pendingRequests = new ConcurrentHashMap<>();
|
||||
|
||||
// Buffer queue: stores raw packets that cannot be sent when no player is online
|
||||
private final Queue<byte[]> messageQueue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public ProxyNetworkService(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
// Register channels
|
||||
plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, CHANNEL);
|
||||
plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, CHANNEL, this);
|
||||
// Register event (used to listen for player join to flush queue)
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,57 +59,110 @@ public class ProxyNetworkService implements NetworkServiceInterface, PluginMessa
|
||||
JsonObject body) {
|
||||
CompletableFuture<NetworkResponse> 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;
|
||||
try {
|
||||
// 1. Prepare request data
|
||||
ProxyNetworkRequest req = new ProxyNetworkRequest(method, endpoint, params, body);
|
||||
String jsonPayload = gson.toJson(req);
|
||||
|
||||
// Safety check: Plugin Message single packet cannot be too large (conservative
|
||||
// limit 30KB)
|
||||
byte[] payloadBytes = jsonPayload.getBytes(StandardCharsets.UTF_8);
|
||||
if (payloadBytes.length > 30000) {
|
||||
future.completeExceptionally(
|
||||
new IllegalArgumentException("Request body too large (>30KB). Protocol limit exceeded."));
|
||||
return future;
|
||||
}
|
||||
|
||||
// 2. Register Future
|
||||
pendingRequests.put(req.getRequestId(), future);
|
||||
|
||||
// 3. Build packet
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF(ProtocolConstants.API_REQUEST);
|
||||
out.writeUTF(jsonPayload); // Length checked above, writeUTF is safe here
|
||||
|
||||
// 4. Try to send or queue
|
||||
trySendOrQueue(out.toByteArray());
|
||||
|
||||
// 5. Set timeout (prevent Future from hanging forever)
|
||||
plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, () -> {
|
||||
CompletableFuture<NetworkResponse> f = pendingRequests.remove(req.getRequestId());
|
||||
if (f != null) {
|
||||
f.complete(new NetworkResponse(504, "Proxy request timed out (Proxy didn't respond or no player online)"));
|
||||
}
|
||||
}, 100L); // 5 seconds timeout
|
||||
|
||||
} catch (Exception e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
|
||||
// 2. Prepare the packet
|
||||
ProxyNetworkRequest req = new ProxyNetworkRequest(method, endpoint, params, body);
|
||||
pendingRequests.put(req.getRequestId(), future);
|
||||
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF(ProtocolConstants.API_REQUEST); // 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<NetworkResponse> f = pendingRequests.remove(req.getRequestId());
|
||||
if (f != null) {
|
||||
f.complete(new NetworkResponse(504, "Proxy request timed out"));
|
||||
}
|
||||
}, 100L); // 5 seconds timeout
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core logic: send if there is a player online, otherwise queue
|
||||
*/
|
||||
private void trySendOrQueue(byte[] message) {
|
||||
Player player = com.google.common.collect.Iterables.getFirst(Bukkit.getOnlinePlayers(), null);
|
||||
|
||||
if (player != null) {
|
||||
player.sendPluginMessage(plugin, CHANNEL, message);
|
||||
} else {
|
||||
// No player online, add to queue
|
||||
// plugin.getLogger().info("[Network] Request queued (No player online)");
|
||||
messageQueue.add(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only flush queued requests when a player joins
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if (messageQueue.isEmpty())
|
||||
return;
|
||||
|
||||
plugin.getLogger().info("[Network] Player joined. Flushing " + messageQueue.size() + " queued requests...");
|
||||
|
||||
// Delay 1 second to ensure player connection is stable
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
|
||||
Player player = event.getPlayer();
|
||||
// Double check: prevent player from leaving immediately after joining
|
||||
if (player == null || !player.isOnline())
|
||||
return;
|
||||
|
||||
while (!messageQueue.isEmpty()) {
|
||||
byte[] msg = messageQueue.poll();
|
||||
if (msg != null) {
|
||||
player.sendPluginMessage(plugin, CHANNEL, msg);
|
||||
}
|
||||
}
|
||||
}, 20L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
|
||||
if (!channel.equals(CHANNEL))
|
||||
return;
|
||||
|
||||
ByteArrayDataInput in = ByteStreams.newDataInput(message);
|
||||
String subChannel = in.readUTF();
|
||||
try {
|
||||
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
|
||||
if (subChannel.equals(ProtocolConstants.API_RESPONSE)) {
|
||||
String reqId = in.readUTF();
|
||||
boolean success = in.readBoolean();
|
||||
String data = in.readUTF();
|
||||
|
||||
CompletableFuture<NetworkResponse> future = pendingRequests.remove(reqId);
|
||||
if (future != null) {
|
||||
if (success) {
|
||||
future.complete(new NetworkResponse(200, data));
|
||||
} else {
|
||||
future.complete(new NetworkResponse(500, data));
|
||||
CompletableFuture<NetworkResponse> future = pendingRequests.remove(reqId);
|
||||
if (future != null) {
|
||||
// If Proxy did not provide a specific status code, map simply here
|
||||
int status = success ? 200 : 500;
|
||||
future.complete(new NetworkResponse(status, data));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("[Network] Failed to parse plugin message: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ 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 online.mineroo.paper.ProxyNetworkService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class BindCommand {
|
||||
@@ -46,6 +48,14 @@ public class BindCommand {
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private void applyMotdToken(String motdToken) {
|
||||
if (plugin.getNetworkService() instanceof ProxyNetworkService) {
|
||||
sendMotdTokenToVelocity(motdToken);
|
||||
} else {
|
||||
plugin.getBindListener().setVerificationToken(motdToken);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -61,12 +71,15 @@ public class BindCommand {
|
||||
// Run the binding process asynchronously to avoid blocking the main thread
|
||||
org.bukkit.Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
Logger logger = plugin.getSLF4JLogger();
|
||||
BindRequest bindRequest = new BindRequest(
|
||||
logger,
|
||||
plugin.getNetworkService());
|
||||
BindRequest bindRequest = plugin.getBindRequest();
|
||||
try {
|
||||
|
||||
String address = plugin.getConfigObject().getServer().getServerBind().getAddress();
|
||||
int port = plugin.getConfigObject().getServer().getServerBind().getPort();
|
||||
String port = String.valueOf(plugin.getConfigObject().getServer().getServerBind().getPort());
|
||||
if (plugin.getNetworkService() instanceof ProxyNetworkService) {
|
||||
address = "$hostname";
|
||||
port = "$port";
|
||||
}
|
||||
|
||||
// 1. Check binding status
|
||||
if (bindRequest.checkBindStatus(address, port).join()) {
|
||||
@@ -80,7 +93,7 @@ public class BindCommand {
|
||||
if (motdOk) {
|
||||
String motdToken = bindRequest.getMotdToken();
|
||||
// Send MOTD token to Velocity
|
||||
sendMotdTokenToVelocity(motdToken);
|
||||
applyMotdToken(motdToken);
|
||||
context.getSource().getSender().sendMessage(plugin.getMessageManager().get("command.bind.server.wait"));
|
||||
try {
|
||||
Thread.sleep(2 * 60 * 1000 + 5000); // 2m 5s
|
||||
@@ -124,7 +137,7 @@ public class BindCommand {
|
||||
plugin.getMessageManager().get("command.bind.server.failed"));
|
||||
} finally {
|
||||
// After binding is complete, you can send a message to clear the MOTD token
|
||||
sendMotdTokenToVelocity(""); // Clear MOTD
|
||||
applyMotdToken(""); // Clear MOTD
|
||||
}
|
||||
});
|
||||
return Command.SINGLE_SUCCESS;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package online.mineroo.paper.listeners;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.ServerListPingEvent;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class BindListener implements Listener {
|
||||
|
||||
private final AtomicReference<String> verificationToken = new AtomicReference<>(null);
|
||||
|
||||
public void setVerificationToken(String token) {
|
||||
if (token == null || token.isEmpty()) {
|
||||
this.verificationToken.set(null);
|
||||
} else {
|
||||
this.verificationToken.set(token);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onServerListPing(ServerListPingEvent event) {
|
||||
String token = verificationToken.get();
|
||||
|
||||
if (token == null || token.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.motd(Component.text(token));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package online.mineroo.paper.listeners;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import online.mineroo.common.BindRequest.PlayerBindStatus;
|
||||
import online.mineroo.common.MessageManager;
|
||||
import online.mineroo.paper.Config;
|
||||
import online.mineroo.paper.MinerooCore;
|
||||
import online.mineroo.paper.utils.PlayerBindDialog;
|
||||
|
||||
@NullMarked
|
||||
public class PlayerBindListener implements Listener {
|
||||
|
||||
private final MinerooCore plugin;
|
||||
|
||||
private Set<UUID> pendingBindPlayers = new HashSet<>();
|
||||
|
||||
public PlayerBindListener(MinerooCore plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
|
||||
MessageManager messageManager = this.plugin.getMessageManager();
|
||||
Config config = this.plugin.getConfigObject();
|
||||
|
||||
Player player = event.getPlayer();
|
||||
|
||||
boolean isForceBind = config.getPlayer().getPlayerBind().isRequired();
|
||||
|
||||
if (isForceBind) {
|
||||
lockPlayer(player);
|
||||
}
|
||||
|
||||
this.plugin.getBindRequest().checkPlayerBindStatus(player.getUniqueId(), null)
|
||||
.thenAccept(response -> {
|
||||
|
||||
// 4. 切回主线程 (Bukkit API 必须在主线程调用)
|
||||
// 这一步非常重要,否则报错 "Asynchronous player tracker update"
|
||||
this.plugin.getServer().getScheduler().runTask(this.plugin, () -> {
|
||||
|
||||
// 检查玩家是否还在同一个服务器 (防止请求期间玩家退出了)
|
||||
if (!player.isOnline())
|
||||
return;
|
||||
|
||||
PlayerBindStatus status = response.getStatus();
|
||||
|
||||
if (status == PlayerBindStatus.BOUND) {
|
||||
if (isForceBind) {
|
||||
unlockPlayer(player);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (status == PlayerBindStatus.ERROR) {
|
||||
this.plugin.getLogger()
|
||||
.warning("Bind check failed for " + player.getName() + ": " + response.getMessage());
|
||||
}
|
||||
|
||||
PlayerBindDialog dialog = new PlayerBindDialog();
|
||||
player.showDialog(dialog.getDialog(messageManager));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (!pendingBindPlayers.contains(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location from = event.getFrom();
|
||||
Location to = event.getTo();
|
||||
|
||||
if (from.getX() == to.getX() && from.getY() == to.getY() && from.getZ() == to.getZ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location newLocation = from.clone();
|
||||
newLocation.setYaw(to.getYaw());
|
||||
newLocation.setPitch(to.getPitch());
|
||||
event.setTo(newLocation);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInteract(PlayerInteractEvent event) {
|
||||
if (isLocked(event.getPlayer()))
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDrop(PlayerDropItemEvent event) {
|
||||
if (isLocked(event.getPlayer()))
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (event.getWhoClicked() instanceof Player player && isLocked(player)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDamage(EntityDamageEvent event) {
|
||||
if (event.getEntity() instanceof Player player && isLocked(player)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
if (isLocked(event.getPlayer()))
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
if (isLocked(event.getPlayer()))
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChat(io.papermc.paper.event.player.AsyncChatEvent event) {
|
||||
if (isLocked(event.getPlayer()))
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
private boolean isLocked(Player player) {
|
||||
return pendingBindPlayers.contains(player.getUniqueId());
|
||||
}
|
||||
|
||||
private void lockPlayer(Player player) {
|
||||
pendingBindPlayers.add(player.getUniqueId());
|
||||
|
||||
player.setWalkSpeed(0f);
|
||||
player.setFlySpeed(0f);
|
||||
|
||||
// player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP,
|
||||
// Integer.MAX_VALUE, 200, false, false));
|
||||
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Integer.MAX_VALUE, 1, false, false));
|
||||
}
|
||||
|
||||
public void unlockPlayer(Player player) {
|
||||
if (pendingBindPlayers.remove(player.getUniqueId())) {
|
||||
player.setWalkSpeed(0.2f);
|
||||
player.setFlySpeed(0.1f);
|
||||
// player.removePotionEffect(PotionEffectType.JUMP);
|
||||
player.removePotionEffect(PotionEffectType.BLINDNESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package online.mineroo.paper.listeners;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public class PlayerJoinListener implements Listener {
|
||||
}
|
||||
Reference in New Issue
Block a user