feat: code
This commit is contained in:
@@ -7,3 +7,4 @@ AlignAfterOpenBracket: BlockIndent
|
|||||||
ColumnLimit: 100
|
ColumnLimit: 100
|
||||||
BinPackArguments: false
|
BinPackArguments: false
|
||||||
AllowAllArgumentsOnNextLine: true
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
BreakStringLiterals: true
|
||||||
|
|||||||
@@ -4,15 +4,13 @@ import com.google.gson.Gson;
|
|||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BindRequest handles server binding and verification with the Mineroo API.
|
* BindRequest handles server binding and verification with the Mineroo API.
|
||||||
@@ -22,7 +20,6 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
* to handle the actual HTTP transport and authentication.
|
* to handle the actual HTTP transport and authentication.
|
||||||
*/
|
*/
|
||||||
public class BindRequest {
|
public class BindRequest {
|
||||||
|
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final NetworkServiceInterface networkService;
|
private final NetworkServiceInterface networkService;
|
||||||
|
|
||||||
@@ -59,7 +56,6 @@ public class BindRequest {
|
|||||||
|
|
||||||
return networkService.getData(path, params)
|
return networkService.getData(path, params)
|
||||||
.thenApply(response -> {
|
.thenApply(response -> {
|
||||||
|
|
||||||
if (response.getStatusCode() != 200) {
|
if (response.getStatusCode() != 200) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -158,7 +154,9 @@ public class BindRequest {
|
|||||||
* @param description The server description (nullable)
|
* @param description The server description (nullable)
|
||||||
* @return A future that completes with true if the binding is successful
|
* @return A future that completes with true if the binding is successful
|
||||||
*/
|
*/
|
||||||
public CompletableFuture<Boolean> finalizeServerBinding(@Nullable String name, @Nullable String description) {
|
public CompletableFuture<Boolean> finalizeServerBinding(
|
||||||
|
@Nullable String name, @Nullable String description
|
||||||
|
) {
|
||||||
String path = "/server/server-bind";
|
String path = "/server/server-bind";
|
||||||
|
|
||||||
JsonObject json = new JsonObject();
|
JsonObject json = new JsonObject();
|
||||||
@@ -180,26 +178,20 @@ public class BindRequest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PlayerBindResponse implements Serializable {
|
public class PlayerBindStatusResponse implements Serializable {
|
||||||
|
@SerializedName("status") private PlayerBindStatusEnum status;
|
||||||
|
|
||||||
@SerializedName("status")
|
@SerializedName("message") private String message;
|
||||||
private PlayerBindStatus status;
|
|
||||||
|
|
||||||
@SerializedName("message")
|
@SerializedName("cached") private boolean cached;
|
||||||
private String message;
|
|
||||||
|
|
||||||
@SerializedName("cached")
|
@SerializedName("timestamp") private long timestamp;
|
||||||
private boolean cached;
|
|
||||||
|
|
||||||
@SerializedName("timestamp")
|
@SerializedName("info") private PlayerBindStatusInfo info;
|
||||||
private long timestamp;
|
|
||||||
|
|
||||||
@SerializedName("info")
|
|
||||||
private PlayerBindInfo info;
|
|
||||||
|
|
||||||
// --- Getters ---
|
// --- Getters ---
|
||||||
|
|
||||||
public PlayerBindStatus getStatus() {
|
public PlayerBindStatusEnum getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,11 +207,11 @@ public class BindRequest {
|
|||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerBindInfo getInfo() {
|
public PlayerBindStatusInfo getInfo() {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(PlayerBindStatus status) {
|
public void setStatus(PlayerBindStatusEnum status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,35 +220,26 @@ public class BindRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static enum PlayerBindStatus {
|
public static enum PlayerBindStatusEnum {
|
||||||
@SerializedName("notBound")
|
@SerializedName("notBound") NOT_BOUND,
|
||||||
NOT_BOUND,
|
|
||||||
|
|
||||||
@SerializedName("bound")
|
@SerializedName("bound") BOUND,
|
||||||
BOUND,
|
|
||||||
|
|
||||||
@SerializedName("conflictUser")
|
@SerializedName("conflictUser") CONFLICT_USER,
|
||||||
CONFLICT_USER,
|
|
||||||
|
|
||||||
@SerializedName("conflictPlayer")
|
@SerializedName("conflictPlayer") CONFLICT_PLAYER,
|
||||||
CONFLICT_PLAYER,
|
|
||||||
|
|
||||||
@SerializedName("error")
|
@SerializedName("error") ERROR
|
||||||
ERROR
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PlayerBindInfo implements Serializable {
|
public static class PlayerBindStatusInfo implements Serializable {
|
||||||
@SerializedName("bound_uuid")
|
@SerializedName("bound_uuid") private String boundUuid;
|
||||||
private String boundUuid;
|
|
||||||
|
|
||||||
@SerializedName("minecraft_uuid")
|
@SerializedName("minecraft_uuid") private String minecraftUuid;
|
||||||
private String minecraftUuid;
|
|
||||||
|
|
||||||
@SerializedName("bound_user_id")
|
@SerializedName("bound_user_id") private Integer boundUserId;
|
||||||
private Integer boundUserId;
|
|
||||||
|
|
||||||
@SerializedName("user_id")
|
@SerializedName("user_id") private Integer userId;
|
||||||
private Integer userId;
|
|
||||||
|
|
||||||
// --- Getters ---
|
// --- Getters ---
|
||||||
|
|
||||||
@@ -285,20 +268,99 @@ public class BindRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlayerBindResponse createErrorResponse(String errorMessage) {
|
private PlayerBindStatusResponse createBindStatusErrorResponse(String errorMessage) {
|
||||||
PlayerBindResponse errorRes = new PlayerBindResponse();
|
PlayerBindStatusResponse errorRes = new PlayerBindStatusResponse();
|
||||||
errorRes.setStatus(PlayerBindStatus.ERROR);
|
errorRes.setStatus(PlayerBindStatusEnum.ERROR);
|
||||||
errorRes.setMessage(errorMessage);
|
errorRes.setMessage(errorMessage);
|
||||||
return errorRes;
|
return errorRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<PlayerBindResponse> checkPlayerBindStatus(UUID player_uuid, String user_email) {
|
public CompletableFuture<PlayerBindStatusResponse> checkPlayerBindStatus(
|
||||||
|
UUID player_uuid, String user_email
|
||||||
|
) {
|
||||||
String path = "/server/user-bind-status";
|
String path = "/server/user-bind-status";
|
||||||
|
|
||||||
Map<String, String> params = new HashMap<>();
|
Map<String, String> params = new HashMap<>();
|
||||||
|
|
||||||
params.put("user_email", user_email);
|
params.put("web_email", user_email);
|
||||||
params.put("player_uuid", player_uuid.toString());
|
params.put("mc_uuid", player_uuid.toString());
|
||||||
|
|
||||||
|
return networkService.getData(path, params)
|
||||||
|
.thenApply(response -> {
|
||||||
|
Gson gson = new Gson();
|
||||||
|
String responseBody = response.getBody();
|
||||||
|
|
||||||
|
if (response.getStatusCode() != 200) {
|
||||||
|
try {
|
||||||
|
return gson.fromJson(responseBody, PlayerBindStatusResponse.class);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return createBindStatusErrorResponse("HTTP Error: " + response.getStatusCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return gson.fromJson(responseBody, PlayerBindStatusResponse.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Mineroo Bind: Failed to parse JSON", e);
|
||||||
|
return createBindStatusErrorResponse("JSON Parse Error");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exceptionally(e -> {
|
||||||
|
logger.error("Mineroo Bind: Network exception", e);
|
||||||
|
return createBindStatusErrorResponse("Network Error: " + e.getMessage());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlayerBindResponse implements Serializable {
|
||||||
|
@SerializedName("status") private PlayerBindEnum status;
|
||||||
|
@SerializedName("timestamp") private long timestamp;
|
||||||
|
@SerializedName("message") private String message;
|
||||||
|
|
||||||
|
public PlayerBindEnum getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(PlayerBindEnum status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum PlayerBindEnum {
|
||||||
|
|
||||||
|
@SerializedName("pending") PENDING,
|
||||||
|
|
||||||
|
@SerializedName("bound") BOUND,
|
||||||
|
|
||||||
|
@SerializedName("expired") EXPIRED,
|
||||||
|
|
||||||
|
@SerializedName("error") ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayerBindResponse createPlayerBindErrorResponse(String errorMessage) {
|
||||||
|
PlayerBindResponse errorRes = new PlayerBindResponse();
|
||||||
|
errorRes.setStatus(PlayerBindEnum.ERROR);
|
||||||
|
errorRes.setMessage(errorMessage);
|
||||||
|
return errorRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<PlayerBindResponse> PlayerBindRequest(
|
||||||
|
String webEmail, String playerUuid, String playerUsername
|
||||||
|
) {
|
||||||
|
String path = "/server/user-bind";
|
||||||
|
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
|
||||||
|
params.put("web_email", webEmail);
|
||||||
|
params.put("mc_uuid", playerUuid);
|
||||||
|
params.put("mc_username", playerUsername);
|
||||||
|
|
||||||
return networkService.getData(path, params)
|
return networkService.getData(path, params)
|
||||||
.thenApply(response -> {
|
.thenApply(response -> {
|
||||||
@@ -309,7 +371,7 @@ public class BindRequest {
|
|||||||
try {
|
try {
|
||||||
return gson.fromJson(responseBody, PlayerBindResponse.class);
|
return gson.fromJson(responseBody, PlayerBindResponse.class);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
return createErrorResponse("HTTP Error: " + response.getStatusCode());
|
return createPlayerBindErrorResponse("HTTP Error: " + response.getStatusCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,12 +379,12 @@ public class BindRequest {
|
|||||||
return gson.fromJson(responseBody, PlayerBindResponse.class);
|
return gson.fromJson(responseBody, PlayerBindResponse.class);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Mineroo Bind: Failed to parse JSON", e);
|
logger.error("Mineroo Bind: Failed to parse JSON", e);
|
||||||
return createErrorResponse("JSON Parse Error");
|
return createPlayerBindErrorResponse("JSON Parse Error");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exceptionally(e -> {
|
.exceptionally(e -> {
|
||||||
logger.error("Mineroo Bind: Network exception", e);
|
logger.error("Mineroo Bind: Network exception", e);
|
||||||
return createErrorResponse("Network Error: " + e.getMessage());
|
return createPlayerBindErrorResponse("Network Error: " + e.getMessage());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
|||||||
import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
|
import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
|
||||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||||
import io.papermc.paper.registry.data.dialog.DialogBase;
|
import io.papermc.paper.registry.data.dialog.DialogBase;
|
||||||
|
import io.papermc.paper.registry.data.dialog.action.DialogAction;
|
||||||
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
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.input.DialogInput;
|
||||||
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||||
@@ -16,16 +17,25 @@ import online.mineroo.common.MessageManager;
|
|||||||
public class MinerooCoreBootstrap implements PluginBootstrap {
|
public class MinerooCoreBootstrap implements PluginBootstrap {
|
||||||
@Override
|
@Override
|
||||||
public void bootstrap(BootstrapContext context) {
|
public void bootstrap(BootstrapContext context) {
|
||||||
|
// TODO: language auto check from config
|
||||||
MessageManager messageManager = new MessageManager();
|
MessageManager messageManager = new MessageManager();
|
||||||
|
|
||||||
ActionButton confirmButton =
|
ActionButton confirmButton = ActionButton.create(
|
||||||
ActionButton.create(messageManager.get("dialog.bind.player.confirm"), null, 100, null);
|
messageManager.get("dialog.bind.player.confirm"),
|
||||||
|
null,
|
||||||
|
100,
|
||||||
|
DialogAction.customClick(Key.key("mineroo:bind_user/confirm"), null)
|
||||||
|
);
|
||||||
|
|
||||||
ActionButton cancelButton =
|
ActionButton cancelButton = ActionButton.create(
|
||||||
ActionButton.create(messageManager.get("dialog.bind.player.cancel"), null, 100, null);
|
messageManager.get("dialog.bind.player.cancel"),
|
||||||
|
null,
|
||||||
|
100,
|
||||||
|
DialogAction.customClick(Key.key("mineroo:bind_user/cancel"), null)
|
||||||
|
);
|
||||||
|
|
||||||
DialogInput usernameInput =
|
DialogInput usernameInput =
|
||||||
DialogInput.text("username", messageManager.get("dialog.bind.player.email")).build();
|
DialogInput.text("user_email", messageManager.get("dialog.bind.player.email")).build();
|
||||||
|
|
||||||
DialogBase dialogBase =
|
DialogBase dialogBase =
|
||||||
DialogBase.builder(messageManager.get("dialog.bind.player.title"))
|
DialogBase.builder(messageManager.get("dialog.bind.player.title"))
|
||||||
@@ -40,7 +50,7 @@ public class MinerooCoreBootstrap implements PluginBootstrap {
|
|||||||
context.getLifecycleManager().registerEventHandler(RegistryEvents.DIALOG.compose().newHandler(
|
context.getLifecycleManager().registerEventHandler(RegistryEvents.DIALOG.compose().newHandler(
|
||||||
event
|
event
|
||||||
-> event.registry().register(
|
-> event.registry().register(
|
||||||
DialogKeys.create(Key.key("papermc:bind_mineroo_user")),
|
DialogKeys.create(Key.key("mineroo:bind_user")),
|
||||||
builder -> builder.base(dialogBase).type(confirmationType)
|
builder -> builder.base(dialogBase).type(confirmationType)
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
package online.mineroo.paper.listeners;
|
package online.mineroo.paper.listeners;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.server.ServerListPingEvent;
|
import org.bukkit.event.server.ServerListPingEvent;
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
public class BindListener implements Listener {
|
public class BindListener implements Listener {
|
||||||
|
|
||||||
private final AtomicReference<String> verificationToken = new AtomicReference<>(null);
|
private final AtomicReference<String> verificationToken = new AtomicReference<>(null);
|
||||||
|
|
||||||
public void setVerificationToken(String token) {
|
public void setVerificationToken(String token) {
|
||||||
|
|||||||
@@ -1,175 +1,167 @@
|
|||||||
|
|
||||||
package online.mineroo.paper.listeners;
|
package online.mineroo.paper.listeners;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent;
|
||||||
import java.util.Set;
|
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;
|
||||||
|
import io.papermc.paper.event.player.PlayerCustomClickEvent;
|
||||||
|
import io.papermc.paper.registry.RegistryAccess;
|
||||||
|
import io.papermc.paper.registry.RegistryKey;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import org.bukkit.Location;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import org.bukkit.entity.Player;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.bukkit.event.EventHandler;
|
import net.kyori.adventure.audience.Audience;
|
||||||
import org.bukkit.event.EventPriority;
|
import net.kyori.adventure.key.Key;
|
||||||
import org.bukkit.event.Listener;
|
import net.kyori.adventure.text.Component;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
import online.mineroo.common.BindRequest;
|
||||||
import org.bukkit.event.entity.EntityDamageEvent;
|
import online.mineroo.common.BindRequest.PlayerBindStatusEnum;
|
||||||
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.Config;
|
||||||
import online.mineroo.paper.MinerooCore;
|
import online.mineroo.paper.MinerooCore;
|
||||||
import online.mineroo.paper.utils.PlayerBindDialog;
|
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
|
@NullMarked
|
||||||
public class PlayerBindListener implements Listener {
|
public class PlayerBindListener implements Listener {
|
||||||
|
|
||||||
private final MinerooCore plugin;
|
private final MinerooCore plugin;
|
||||||
|
|
||||||
private Set<UUID> pendingBindPlayers = new HashSet<>();
|
private final Map<UUID, CompletableFuture<Boolean>> awaitingResponse = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public PlayerBindListener(MinerooCore plugin) {
|
public PlayerBindListener(MinerooCore plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerConfigure(AsyncPlayerConnectionConfigureEvent event) {
|
||||||
|
|
||||||
MessageManager messageManager = this.plugin.getMessageManager();
|
|
||||||
Config config = this.plugin.getConfigObject();
|
Config config = this.plugin.getConfigObject();
|
||||||
|
|
||||||
Player player = event.getPlayer();
|
if (!config.getPlayer().getPlayerBind().isRequired()) {
|
||||||
|
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Location from = event.getFrom();
|
UUID uuid = event.getConnection().getProfile().getId();
|
||||||
Location to = event.getTo();
|
if (uuid == null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (from.getX() == to.getX() && from.getY() == to.getY() && from.getZ() == to.getZ()) {
|
try {
|
||||||
|
var response = this.plugin.getBindRequest()
|
||||||
|
.checkPlayerBindStatus(uuid, event.getConnection().getProfile().getName())
|
||||||
|
.join();
|
||||||
|
|
||||||
|
PlayerBindStatusEnum status = response.getStatus();
|
||||||
|
|
||||||
|
if (status == PlayerBindStatusEnum.BOUND) {
|
||||||
|
return;
|
||||||
|
} else if (status == PlayerBindStatusEnum.NOT_BOUND) {
|
||||||
|
Dialog dialog = RegistryAccess.registryAccess()
|
||||||
|
.getRegistry(RegistryKey.DIALOG)
|
||||||
|
.get(Key.key("mineroo:bind_user"));
|
||||||
|
if (dialog == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerConfigurationConnection connection = event.getConnection();
|
||||||
|
|
||||||
|
UUID uniqueId = connection.getProfile().getId();
|
||||||
|
|
||||||
|
if (uniqueId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletableFuture<Boolean> dialogResponse = new CompletableFuture<>();
|
||||||
|
dialogResponse.completeOnTimeout(false, 1, TimeUnit.MINUTES);
|
||||||
|
awaitingResponse.put(uniqueId, dialogResponse);
|
||||||
|
|
||||||
|
Audience audience = connection.getAudience();
|
||||||
|
audience.showDialog(dialog);
|
||||||
|
|
||||||
|
if (!dialogResponse.join()) {
|
||||||
|
audience.closeDialog();
|
||||||
|
connection.disconnect(Component.text("You hate Paper-chan :(", NamedTextColor.RED));
|
||||||
|
}
|
||||||
|
awaitingResponse.remove(uniqueId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
event.getConnection().disconnect(
|
||||||
|
Component.text("服务器内部错误,请稍后重试", NamedTextColor.RED)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.plugin.getLogger().severe("Failed to check bind status for " + uuid);
|
||||||
|
e.printStackTrace();
|
||||||
|
event.getConnection().disconnect(
|
||||||
|
Component.text("服务器内部错误,请稍后重试", NamedTextColor.RED)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
void onHandleDialog(PlayerCustomClickEvent event) {
|
||||||
|
Logger logger = plugin.getSLF4JLogger();
|
||||||
|
|
||||||
|
logger.info("12313213131231");
|
||||||
|
|
||||||
|
// Handle custom click only for configuration connection.
|
||||||
|
if (!(event.getCommonConnection()
|
||||||
|
instanceof PlayerConfigurationConnection configurationConnection)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Location newLocation = from.clone();
|
UUID uniqueId = configurationConnection.getProfile().getId();
|
||||||
newLocation.setYaw(to.getYaw());
|
|
||||||
newLocation.setPitch(to.getPitch());
|
|
||||||
event.setTo(newLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
if (uniqueId == null) {
|
||||||
public void onInteract(PlayerInteractEvent event) {
|
return;
|
||||||
if (isLocked(event.getPlayer()))
|
}
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
Key key = event.getIdentifier();
|
||||||
public void onDrop(PlayerDropItemEvent event) {
|
|
||||||
if (isLocked(event.getPlayer()))
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
if (key.equals(Key.key("mineroo:bind_user/confirm"))) {
|
||||||
public void onInventoryClick(InventoryClickEvent event) {
|
DialogResponseView view = event.getDialogResponseView();
|
||||||
if (event.getWhoClicked() instanceof Player player && isLocked(player)) {
|
if (view == null) {
|
||||||
event.setCancelled(true);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String user_email = view.getText("user_email");
|
||||||
|
|
||||||
|
if (event.getCommonConnection() instanceof PlayerConfigurationConnection conn) {
|
||||||
|
BindRequest bindRequest = plugin.getBindRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
setConnectionJoinResult(uniqueId, true);
|
||||||
|
|
||||||
|
} else if (key.equals(Key.key("mineroo:bind_user/cancel"))) {
|
||||||
|
// If it is the same as the agree one, set the result to true.
|
||||||
|
|
||||||
|
setConnectionJoinResult(uniqueId, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onDamage(EntityDamageEvent event) {
|
void onConnectionClose(PlayerConnectionCloseEvent event) {
|
||||||
if (event.getEntity() instanceof Player player && isLocked(player)) {
|
awaitingResponse.remove(event.getPlayerUniqueId());
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
/**
|
||||||
public void onBlockBreak(BlockBreakEvent event) {
|
|
||||||
if (isLocked(event.getPlayer()))
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
* Simple utility method for setting a connection's dialog response result.
|
||||||
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) {
|
private void setConnectionJoinResult(UUID uniqueId, boolean value) {
|
||||||
return pendingBindPlayers.contains(player.getUniqueId());
|
CompletableFuture<Boolean> future = awaitingResponse.get(uniqueId);
|
||||||
}
|
|
||||||
|
|
||||||
private void lockPlayer(Player player) {
|
if (future != null) {
|
||||||
pendingBindPlayers.add(player.getUniqueId());
|
future.complete(value);
|
||||||
|
|
||||||
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,34 +0,0 @@
|
|||||||
package online.mineroo.paper.utils;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import io.papermc.paper.dialog.Dialog;
|
|
||||||
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 online.mineroo.common.MessageManager;
|
|
||||||
|
|
||||||
public class PlayerBindDialog {
|
|
||||||
public Dialog getDialog(MessageManager messageManager) {
|
|
||||||
|
|
||||||
Dialog dialog = Dialog.create(builder -> builder.empty()
|
|
||||||
.base(DialogBase.builder(messageManager.get("dialog.bind.player.title"))
|
|
||||||
.body(List.of(DialogBody.plainMessage(messageManager.get("dialog.bind.player.content"))))
|
|
||||||
.inputs(
|
|
||||||
List.of(
|
|
||||||
// username
|
|
||||||
DialogInput.text("username", messageManager.get("dialog.bind.player.email")).build()
|
|
||||||
// ...
|
|
||||||
))
|
|
||||||
.build())
|
|
||||||
.type(DialogType.confirmation(
|
|
||||||
ActionButton.create(messageManager.get("dialog.bind.player.confirm"), null, 100, null),
|
|
||||||
ActionButton.create(messageManager.get("dialog.bind.player.cancel"), null, 100, null)
|
|
||||||
// ...
|
|
||||||
)));
|
|
||||||
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
6
paper/src/main/resources/paper-plugin.yml
Normal file
6
paper/src/main/resources/paper-plugin.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
name: MinerooCore
|
||||||
|
version: "1.0"
|
||||||
|
main: "online.mineroo.paper.MinerooCore"
|
||||||
|
description: Paper Test Plugin
|
||||||
|
api-version: "1.21.10"
|
||||||
|
bootstrapper: "online.mineroo.paper.MinerooCoreBootstrap"
|
||||||
@@ -3,12 +3,10 @@ package online.mineroo.velocity.listeners;
|
|||||||
import com.velocitypowered.api.event.Subscribe;
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||||
import com.velocitypowered.api.proxy.server.ServerPing;
|
import com.velocitypowered.api.proxy.server.ServerPing;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
public class BindListener {
|
public class BindListener {
|
||||||
|
|
||||||
private final AtomicReference<String> verificationToken = new AtomicReference<>(null);
|
private final AtomicReference<String> verificationToken = new AtomicReference<>(null);
|
||||||
|
|
||||||
public void setVerificationToken(String token) {
|
public void setVerificationToken(String token) {
|
||||||
|
|||||||
Reference in New Issue
Block a user