From a3841215d14ba3c7b346255e03dad48c489433d9 Mon Sep 17 00:00:00 2001 From: mrhua269 Date: Sun, 8 Feb 2026 09:14:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=80=E4=BA=9B=E9=87=8D=E6=9E=84()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../peek/handler/PeekStateHandler.java | 119 +++++++------- .../peek/handler/PlayerStateRestorer.java | 66 ++++---- .../peek/handler/RangeChecker.java | 148 +++++++++--------- .../peek/listener/PeekListener.java | 2 +- .../peek/manager/CooldownManager.java | 3 +- .../peek/manager/PrivacyManager.java | 31 ++-- .../peek/util/PlayerStateUtil.java | 57 +++---- 7 files changed, 208 insertions(+), 218 deletions(-) diff --git a/src/main/java/ict/minesunshineone/peek/handler/PeekStateHandler.java b/src/main/java/ict/minesunshineone/peek/handler/PeekStateHandler.java index 608ae6a..20ea3e5 100644 --- a/src/main/java/ict/minesunshineone/peek/handler/PeekStateHandler.java +++ b/src/main/java/ict/minesunshineone/peek/handler/PeekStateHandler.java @@ -52,6 +52,7 @@ public void startPeek(Player peeker, Player target) { } // 防止并发修改 + final PeekData data; synchronized (activePeeks) { if (activePeeks.containsKey(peeker.getUniqueId())) { plugin.getMessages().send(peeker, "already-peeking"); @@ -59,7 +60,7 @@ public void startPeek(Player peeker, Player target) { } logDebug("Starting peek: %s -> %s", peeker.getName(), target.getName()); - PeekData data = new PeekData( + data = new PeekData( peeker.getLocation().clone(), peeker.getGameMode(), target.getUniqueId(), @@ -70,12 +71,13 @@ public void startPeek(Player peeker, Player target) { peeker.getActivePotionEffects()); activePeeks.put(peeker.getUniqueId(), data); - plugin.getStateManager().savePlayerState(peeker, data); - plugin.getStatisticsManager().recordPeekStart(peeker, target); - - teleportAndSetGameMode(peeker, target); } + plugin.getStateManager().savePlayerState(peeker, data); + plugin.getStatisticsManager().recordPeekStart(peeker, target); + + teleportAndSetGameMode(peeker, target); + // 检查是否静默 peek(有 bypass 权限) boolean silentPeek = plugin.getTargetHandler().shouldSilentPeek(peeker); @@ -246,69 +248,68 @@ public void endPeek(Player peeker) { // ==================== 私有方法 ==================== private void teleportAndSetGameMode(Player peeker, Player target) { + final Runnable onFailed = () -> { + plugin.getMessages().send(peeker, "teleport-failed"); + endPeek(peeker); + }; + // 先切换游戏模式 - plugin.getServer().getRegionScheduler().run(plugin, peeker.getLocation(), task -> { - try { - // 清理骑乘状态,准备进入旁观者模式 - PlayerStateUtil.prepareForSpectatorMode(peeker, plugin.getLogger()); - - // 设置为旁观模式 - peeker.setGameMode(GameMode.SPECTATOR); - - // 等待2 tick后再传送 - plugin.getServer().getRegionScheduler().runDelayed(plugin, peeker.getLocation(), delayedTask -> { - peeker.teleportAsync(target.getLocation(), TeleportCause.PLUGIN).thenAccept(success -> { - if (!success) { - plugin.getMessages().send(peeker, "teleport-failed"); - endPeek(peeker); - } else { - // 传送成功后,使用玩家的实体调度器确保在正确线程执行 - peeker.getScheduler().run(plugin, scheduledTask -> { - bossBarHandler.createDistanceBossBar(peeker, target); - startNormalRangeChecker(peeker, target); - }, null); - } - }); - }, 2L); // 2 tick 延迟 - } catch (Exception e) { - plugin.getLogger().warning(String.format("为玩家 %s 切换游戏模式时发生错误", peeker.getName())); - peeker.setSneaking(false); // 确保异常时也恢复状态 - endPeek(peeker); + final boolean firstRoundScheduled = peeker.getScheduler().execute(plugin, () -> { + // 清理骑乘状态,准备进入旁观者模式 + PlayerStateUtil.prepareForSpectatorMode(peeker); + + // 设置为旁观模式 + peeker.setGameMode(GameMode.SPECTATOR); + + // 等待2 tick后再传送 + final boolean secondRoundScheduled = peeker.getScheduler().execute(plugin, () -> { + peeker.teleportAsync(target.getLocation(), TeleportCause.PLUGIN).thenAccept(success -> { + if (!success) { + onFailed.run(); + } else { + // 传送成功后,使用玩家的实体调度器确保在正确线程执行 + bossBarHandler.createDistanceBossBar(peeker, target); + startNormalRangeChecker(peeker, target); + } + }); + }, onFailed, 2L); // 2 tick 延迟 + + if (!secondRoundScheduled) { + onFailed.run(); } - }); + }, onFailed, 1L); + + if (!firstRoundScheduled) { + onFailed.run(); + } } private void setSelfPeekGameMode(Player peeker) { - plugin.getServer().getRegionScheduler().run(plugin, peeker.getLocation(), task -> { - try { - if (!peeker.isOnline()) { - plugin.getLogger().warning(String.format("玩家 %s 在设置自我观察模式时已离线", peeker.getName())); - endPeek(peeker, false); - return; - } + peeker.getScheduler().execute(plugin, () -> { + // 这里如果玩家离线了调度器会自动退役 + /*if (!peeker.isOnline()) { + plugin.getLogger().warning(String.format("玩家 %s 在设置自我观察模式时已离线", peeker.getName())); + endPeek(peeker, false); + return; + }*/ - if (peeker.isDead()) { - plugin.getLogger().warning(String.format("玩家 %s 在设置自我观察模式时已死亡", peeker.getName())); - plugin.getMessages().send(peeker, "cannot-peek-while-dead"); - endPeek(peeker, false); - return; - } + if (peeker.isDead()) { + plugin.getSLF4JLogger().warn("玩家 {} 在设置自我观察模式时已死亡", peeker.getName()); + plugin.getMessages().send(peeker, "cannot-peek-while-dead"); + endPeek(peeker, false); + return; + } - // 清理骑乘状态,准备进入旁观者模式 - PlayerStateUtil.prepareForSpectatorMode(peeker, plugin.getLogger()); + // 清理骑乘状态,准备进入旁观者模式 + PlayerStateUtil.prepareForSpectatorMode(peeker); - peeker.setGameMode(GameMode.SPECTATOR); + peeker.setGameMode(GameMode.SPECTATOR); - logDebug("Successfully set self peek game mode for player: %s", peeker.getName()); - } catch (Exception e) { - plugin.getLogger().warning(String.format("为玩家 %s 设置自我观察模式时发生错误: %s", peeker.getName(), e.getMessage())); - if (plugin.getConfig().getBoolean("debug", false)) { - e.printStackTrace(); - } - peeker.setSneaking(false); // 确保异常时也恢复状态 - endPeek(peeker); - } - }); + logDebug("Successfully set self peek game mode for player: %s", peeker.getName()); + }, () -> { + plugin.getSLF4JLogger().warn("玩家 {} 在设置自我观察模式时已离线", peeker.getName()); + endPeek(peeker, false); + }, 1L); } private void startNormalRangeChecker(Player peeker, Player target) { diff --git a/src/main/java/ict/minesunshineone/peek/handler/PlayerStateRestorer.java b/src/main/java/ict/minesunshineone/peek/handler/PlayerStateRestorer.java index 22d078d..299ed6f 100644 --- a/src/main/java/ict/minesunshineone/peek/handler/PlayerStateRestorer.java +++ b/src/main/java/ict/minesunshineone/peek/handler/PlayerStateRestorer.java @@ -16,6 +16,7 @@ * 包括传送、游戏模式、生命值、饥饿度、药水效果等 */ public class PlayerStateRestorer { + private static final Vector ZERO_VECTOR = new Vector(0, 0, 0); private final PeekPlugin plugin; @@ -30,25 +31,29 @@ public PlayerStateRestorer(PeekPlugin plugin) { * @param data PeekData 数据 */ public void restorePlayerState(Player peeker, PeekData data) { - plugin.getServer().getRegionScheduler().run(plugin, data.getOriginalLocation(), task -> { + final Runnable onFailed = () -> handleTeleportFailure(peeker, data); + + final boolean scheduled = peeker.getScheduler().execute(plugin, ()-> { // 强制清理任何骑乘/附身状态,防止卡在旁观者模式 - PlayerStateUtil.forceExitRidingState(peeker, plugin.getLogger()); + PlayerStateUtil.forceExitRidingState(peeker); // 在传送前先清除动量 - peeker.setVelocity(new Vector(0, 0, 0)); + peeker.setVelocity(ZERO_VECTOR); peeker.teleportAsync(data.getOriginalLocation(), TeleportCause.PLUGIN).thenAccept(success -> { if (success) { // 传送成功后再改变游戏模式 - plugin.getServer().getRegionScheduler().run(plugin, data.getOriginalLocation(), modeTask -> { - applyRestoredState(peeker, data); - }); + applyRestoredState(peeker, data); } else { - handleTeleportFailure(peeker, data); + onFailed.run(); } }); - }); + }, onFailed, 1L); + + if (!scheduled) { + onFailed.run(); + } } /** @@ -62,28 +67,31 @@ public void handleTeleportFailure(Player peeker, PeekData data) { "无法将玩家 %s 传送回原位置,正在尝试传送到重生点", peeker.getName())); - Location spawnLoc = resolveSpawnLocation(peeker); + final Location spawnLoc = resolveSpawnLocation(peeker); + + final Runnable onFailed = () -> { + plugin.getLogger().severe(String.format( + "未找到可用的重生点,强制恢复玩家 %s 的状态", + peeker.getName())); + forceStateRestoreWithoutTeleport(peeker, data); + }; if (spawnLoc != null) { - plugin.getServer().getRegionScheduler().run(plugin, spawnLoc, spawnTask -> { + final boolean scheduled = peeker.getScheduler().execute(plugin, () -> { peeker.teleportAsync(spawnLoc, TeleportCause.PLUGIN).thenAccept(spawnSuccess -> { if (spawnSuccess) { - plugin.getServer().getRegionScheduler().run(plugin, spawnLoc, modeTask -> { - applyRestoredState(peeker, data); - }); + applyRestoredState(peeker, data); } else { - plugin.getLogger().severe(String.format( - "无法将玩家 %s 传送到任何安全位置", - peeker.getName())); - forceStateRestoreWithoutTeleport(peeker, data); + onFailed.run(); } }); - }); + }, onFailed, 1L); + + if (!scheduled) { + onFailed.run(); + } } else { - plugin.getLogger().severe(String.format( - "未找到可用的重生点,强制恢复玩家 %s 的状态", - peeker.getName())); - forceStateRestoreWithoutTeleport(peeker, data); + onFailed.run(); } plugin.getMessages().send(peeker, "teleport-failed"); @@ -97,17 +105,13 @@ public void handleTeleportFailure(Player peeker, PeekData data) { */ public Location resolveSpawnLocation(Player peeker) { Location respawnLocation = peeker.getRespawnLocation(); + if (respawnLocation != null) { return respawnLocation; } - if (peeker.getWorld() != null) { - return peeker.getWorld().getSpawnLocation(); - } + return peeker.getWorld().getSpawnLocation(); - return plugin.getServer().getWorlds().isEmpty() - ? null - : plugin.getServer().getWorlds().get(0).getSpawnLocation(); } /** @@ -117,9 +121,7 @@ public Location resolveSpawnLocation(Player peeker) { * @param data PeekData 数据 */ public void forceStateRestoreWithoutTeleport(Player peeker, PeekData data) { - plugin.getServer().getRegionScheduler().run(plugin, peeker.getLocation(), modeTask -> { - applyRestoredState(peeker, data); - }); + applyRestoredState(peeker, data); } /** @@ -133,7 +135,7 @@ public void applyRestoredState(Player peeker, PeekData data) { peeker.setVelocity(new Vector(0, 0, 0)); // 再次强制清理骑乘/附身状态,确保万无一失 - PlayerStateUtil.forceExitRidingState(peeker, plugin.getLogger()); + PlayerStateUtil.forceExitRidingState(peeker); peeker.setGameMode(data.getOriginalGameMode()); double maxHealth = getMaxHealth(peeker); diff --git a/src/main/java/ict/minesunshineone/peek/handler/RangeChecker.java b/src/main/java/ict/minesunshineone/peek/handler/RangeChecker.java index 103bd0c..6bd35f7 100644 --- a/src/main/java/ict/minesunshineone/peek/handler/RangeChecker.java +++ b/src/main/java/ict/minesunshineone/peek/handler/RangeChecker.java @@ -1,6 +1,7 @@ package ict.minesunshineone.peek.handler; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.UUID; import java.util.function.Consumer; @@ -20,7 +21,6 @@ public class RangeChecker { private final PeekPlugin plugin; private final Map rangeCheckers = new HashMap<>(); - private final Object rangeCheckersLock = new Object(); private final double maxPeekDistance; public RangeChecker(PeekPlugin plugin) { @@ -42,45 +42,50 @@ public void startRangeChecker(Player peeker, Player target, Runnable onTargetOffline, Consumer onDistanceUpdate, Runnable onDifferentWorld) { - synchronized (rangeCheckersLock) { + synchronized (this) { // 先停止已有的检查器(如果有的话) ScheduledTask existingTask = rangeCheckers.remove(peeker.getUniqueId()); if (existingTask != null) { existingTask.cancel(); } - ScheduledTask task = plugin.getServer().getRegionScheduler().runAtFixedRate(plugin, - target.getLocation(), // 使用target的位置而不是peeker的位置 + ScheduledTask task = target.getScheduler().runAtFixedRate(plugin, scheduledTask -> { - if (!target.isOnline()) { - onTargetOffline.run(); + // 检查观察者是否死亡 + if (peeker.isDead()) { return; } - try { - // 检查观察者是否死亡 - if (peeker.isDead()) { - return; + if (peeker.getWorld().equals(target.getWorld())) { + double distance = peeker.getLocation().distance(target.getLocation()); + onDistanceUpdate.accept(distance); + if (distance > maxPeekDistance) { + onRangeExceeded.run(); } + } else { + // 跨维度 + onDifferentWorld.run(); + } + }, + () -> { + // 实体调度器退役 -> 目标已经离线或者切换回了配置状态 + onTargetOffline.run(); - if (peeker.getWorld().equals(target.getWorld())) { - double distance = peeker.getLocation().distance(target.getLocation()); - onDistanceUpdate.accept(distance); - if (distance > maxPeekDistance) { - onRangeExceeded.run(); - } - } else { - // 跨维度 - onDifferentWorld.run(); - } - } catch (Exception e) { - plugin.getLogger().warning(String.format("距离检查时发生错误:%s", e.getMessage())); - onRangeExceeded.run(); + // 清理 + synchronized (RangeChecker.this) { + rangeCheckers.remove(peeker.getUniqueId()); } }, 1L, 10L); - rangeCheckers.put(peeker.getUniqueId(), task); + // 实体调度器没有退役,正常添加到任务列表中 + if (task != null) { + rangeCheckers.put(peeker.getUniqueId(), task); + return; + } + + // 实体调度器退役 -> 目标已经离线或者切换回了配置状态 + onTargetOffline.run(); } } @@ -100,60 +105,54 @@ public void startSelfRangeChecker(Player peeker, Location originalLocation, Runnable onWorldChanged, java.util.function.Consumer onDistanceUpdate, Runnable onError) { - synchronized (rangeCheckersLock) { + synchronized (this) { // 先停止已有的检查器(如果有的话) stopRangeChecker(peeker); - ScheduledTask task = plugin.getServer().getRegionScheduler().runAtFixedRate(plugin, - originalLocation, // 使用原始位置 + ScheduledTask task = peeker.getScheduler().runAtFixedRate(plugin, scheduledTask -> { - // 检查玩家是否在线 - if (!peeker.isOnline()) { - logDebug("Player %s went offline during self peek, ending peek", peeker.getName()); - onError.run(); - return; + // 检查观察者是否死亡(与普通peek逻辑一致) + if (peeker.isDead()) { + logDebug("Player %s died during self peek, but continuing to monitor for respawn", peeker.getName()); + return; // 不立即结束,等待重生处理 } - try { - // 检查观察者是否死亡(与普通peek逻辑一致) - if (peeker.isDead()) { - logDebug("Player %s died during self peek, but continuing to monitor for respawn", peeker.getName()); - return; // 不立即结束,等待重生处理 - } - - // 额外的状态检查 - PeekData data = getPeekData.get(); - if (data == null) { - logDebug("PeekData for player %s is null, stopping range checker", peeker.getName()); - scheduledTask.cancel(); - return; - } + // 额外的状态检查 + PeekData data = getPeekData.get(); + if (data == null) { + logDebug("PeekData for player %s is null, stopping range checker", peeker.getName()); + scheduledTask.cancel(); + return; + } - // 检查是否超出距离限制(相对于原始位置) - if (peeker.getWorld().equals(originalLocation.getWorld())) { - double distance = peeker.getLocation().distance(originalLocation); - // 更新距离显示 - onDistanceUpdate.accept(distance); - if (distance > maxPeekDistance) { - logDebug("Player %s exceeded self peek distance: %.2f > %.2f", - peeker.getName(), distance, maxPeekDistance); - onRangeExceeded.run(); - } - } else { - // 如果换了世界,自动结束自我观察 - logDebug("Player %s changed world during self peek", peeker.getName()); - onWorldChanged.run(); - } - } catch (Exception e) { - plugin.getLogger().warning(String.format("自我观察距离检查时发生错误:%s", e.getMessage())); - if (plugin.getConfig().getBoolean("debug", false)) { - e.printStackTrace(); + // 检查是否超出距离限制(相对于原始位置) + if (peeker.getWorld().equals(originalLocation.getWorld())) { + double distance = peeker.getLocation().distance(originalLocation); + // 更新距离显示 + onDistanceUpdate.accept(distance); + if (distance > maxPeekDistance) { + logDebug("Player %s exceeded self peek distance: %.2f > %.2f", + peeker.getName(), distance, maxPeekDistance); + onRangeExceeded.run(); } - onError.run(); + } else { + // 如果换了世界,自动结束自我观察 + logDebug("Player %s changed world during self peek", peeker.getName()); + onWorldChanged.run(); } }, + () -> { + logDebug("Player %s went offline during self peek, ending peek", peeker.getName()); + onError.run(); + }, 1L, 10L); + if (task == null) { + logDebug("Player %s went offline during self peek, ending peek", peeker.getName()); + onError.run(); + return; + } + rangeCheckers.put(peeker.getUniqueId(), task); logDebug("Started self range checker for player: %s", peeker.getName()); } @@ -164,8 +163,9 @@ public void startSelfRangeChecker(Player peeker, Location originalLocation, * @param peeker 观察者 */ public void stopRangeChecker(Player peeker) { - synchronized (rangeCheckersLock) { + synchronized (this) { ScheduledTask task = rangeCheckers.remove(peeker.getUniqueId()); + if (task != null) { task.cancel(); } @@ -184,11 +184,17 @@ public double getMaxPeekDistance() { * 清理所有检查器 */ public void cleanup() { - synchronized (rangeCheckersLock) { - new HashMap<>(rangeCheckers).forEach((peeker, task) -> { + synchronized (this) { + final Iterator> checkerEntryIterator = rangeCheckers.entrySet().iterator(); + + while (checkerEntryIterator.hasNext()) { + final Map.Entry entry = checkerEntryIterator.next(); + + final ScheduledTask task = entry.getValue(); task.cancel(); - rangeCheckers.remove(peeker); - }); + + checkerEntryIterator.remove(); + } } } diff --git a/src/main/java/ict/minesunshineone/peek/listener/PeekListener.java b/src/main/java/ict/minesunshineone/peek/listener/PeekListener.java index 86f4ea7..65b1e35 100644 --- a/src/main/java/ict/minesunshineone/peek/listener/PeekListener.java +++ b/src/main/java/ict/minesunshineone/peek/listener/PeekListener.java @@ -93,7 +93,7 @@ public void onPlayerDeath(PlayerDeathEvent event) { // 如果玩家死亡时有发出的请求,取消所有请求 for (Map.Entry> entry - : new HashMap<>(plugin.getPrivacyManager().getPendingRequests()).entrySet()) { + : plugin.getPrivacyManager().getPendingRequests().entrySet()) { Map requests = entry.getValue(); if (requests.containsKey(player.getUniqueId())) { // 取消该玩家发出的请求 diff --git a/src/main/java/ict/minesunshineone/peek/manager/CooldownManager.java b/src/main/java/ict/minesunshineone/peek/manager/CooldownManager.java index a326608..c0fb1f3 100644 --- a/src/main/java/ict/minesunshineone/peek/manager/CooldownManager.java +++ b/src/main/java/ict/minesunshineone/peek/manager/CooldownManager.java @@ -3,6 +3,7 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import org.bukkit.entity.Player; @@ -10,7 +11,7 @@ public class CooldownManager { - private final Map cooldowns = new HashMap<>(); + private final Map cooldowns = new ConcurrentHashMap<>(); private final int cooldownDuration; public CooldownManager(PeekPlugin plugin) { diff --git a/src/main/java/ict/minesunshineone/peek/manager/PrivacyManager.java b/src/main/java/ict/minesunshineone/peek/manager/PrivacyManager.java index fec1c0a..91a9237 100644 --- a/src/main/java/ict/minesunshineone/peek/manager/PrivacyManager.java +++ b/src/main/java/ict/minesunshineone/peek/manager/PrivacyManager.java @@ -136,7 +136,7 @@ public String debugPrivacyStatus(Player player) { /** * 取消玩家的所有待处理请求 */ - private void cancelAllPendingRequests(Player player) { + private synchronized void cancelAllPendingRequests(Player player) { UUID playerUuid = player.getUniqueId(); // 取消作为目标的所有请求 @@ -201,8 +201,7 @@ public void sendPeekRequest(Player peeker, Player target) { playSound(target, "privacy.sounds.request"); // 设置超时任务 - ScheduledTask timeoutTask = plugin.getServer().getRegionScheduler().runDelayed(plugin, - target.getLocation(), + ScheduledTask timeoutTask = plugin.getServer().getGlobalRegionScheduler().runDelayed(plugin, task -> { if (removePendingRequest(peeker, target)) { plugin.getMessages().send(peeker, "request-timeout"); @@ -213,8 +212,10 @@ public void sendPeekRequest(Player peeker, Player target) { requestTimeout * 20L); // 保存请求 - pendingRequests.computeIfAbsent(targetUuid, k -> new HashMap<>()) - .put(peekerUuid, timeoutTask); + synchronized (this) { + pendingRequests.computeIfAbsent(targetUuid, k -> new HashMap<>()) + .put(peekerUuid, timeoutTask); + } } public void handleRequestResponse(Player target, Player peeker, boolean accepted) { @@ -235,12 +236,12 @@ public void handleRequestResponse(Player target, Player peeker, boolean accepted } } - private boolean hasPendingRequest(Player peeker, Player target) { + private synchronized boolean hasPendingRequest(Player peeker, Player target) { Map targetRequests = pendingRequests.get(target.getUniqueId()); return targetRequests != null && targetRequests.containsKey(peeker.getUniqueId()); } - public boolean removePendingRequest(Player peeker, Player target) { + public synchronized boolean removePendingRequest(Player peeker, Player target) { Map targetRequests = pendingRequests.get(target.getUniqueId()); if (targetRequests != null) { ScheduledTask task = targetRequests.remove(peeker.getUniqueId()); @@ -255,14 +256,14 @@ public boolean removePendingRequest(Player peeker, Player target) { return false; } - private void setRequestCooldown(Player peeker, Player target) { + private synchronized void setRequestCooldown(Player peeker, Player target) { if (cooldownEnabled) { String key = getCooldownKey(peeker.getUniqueId(), target.getUniqueId()); requestCooldowns.put(key, System.currentTimeMillis()); } } - private boolean isOnRequestCooldown(Player peeker, Player target) { + private synchronized boolean isOnRequestCooldown(Player peeker, Player target) { if (!cooldownEnabled || peeker.hasPermission("peek.nocooldown")) { return false; } @@ -276,7 +277,7 @@ private boolean isOnRequestCooldown(Player peeker, Player target) { return System.currentTimeMillis() - lastRequest < cooldownDuration * 1000L; } - private int getRemainingRequestCooldown(Player peeker, Player target) { + private synchronized int getRemainingRequestCooldown(Player peeker, Player target) { if (!cooldownEnabled || peeker.hasPermission("peek.nocooldown")) { return 0; } @@ -307,7 +308,7 @@ private void playSound(Player player, String configPath) { } } - public void cancelAllRequests(Player player) { + public synchronized void cancelAllRequests(Player player) { UUID playerUuid = player.getUniqueId(); // 取消作为目标的请求 @@ -328,7 +329,7 @@ public void cancelAllRequests(Player player) { pendingRequests.values().removeIf(Map::isEmpty); } - public void handleAccept(Player player) { + public synchronized void handleAccept(Player player) { // 获取最近的请求者 UUID playerUuid = player.getUniqueId(); Map requests = pendingRequests.get(playerUuid); @@ -349,7 +350,7 @@ public void handleAccept(Player player) { handleRequestResponse(player, peeker, true); } - public void handleDeny(Player player) { + public synchronized void handleDeny(Player player) { // 获取最近的请求者 UUID playerUuid = player.getUniqueId(); Map requests = pendingRequests.get(playerUuid); @@ -369,7 +370,7 @@ public void handleDeny(Player player) { } } - public Map> getPendingRequests() { - return pendingRequests; + public synchronized Map> getPendingRequests() { + return new HashMap<>(pendingRequests); // TODO 好罢这玩意我也不想重构,先用COW顶着罢() } } diff --git a/src/main/java/ict/minesunshineone/peek/util/PlayerStateUtil.java b/src/main/java/ict/minesunshineone/peek/util/PlayerStateUtil.java index 55929be..ff769b3 100644 --- a/src/main/java/ict/minesunshineone/peek/util/PlayerStateUtil.java +++ b/src/main/java/ict/minesunshineone/peek/util/PlayerStateUtil.java @@ -1,7 +1,5 @@ package ict.minesunshineone.peek.util; -import java.util.logging.Logger; - import org.bukkit.GameMode; import org.bukkit.entity.Player; @@ -20,46 +18,28 @@ private PlayerStateUtil() { * 通过模拟shift并调用leaveVehicle确保彻底解除骑乘关系 * * @param player 玩家 - * @param logger 日志记录器(可选,用于记录错误) */ - public static void forceExitRidingState(Player player, Logger logger) { - try { - // 先模拟按下shift键 - player.setSneaking(true); - - // 如果在旁观者模式下附身了其他实体,先退出附身 - if (player.getGameMode() == GameMode.SPECTATOR && player.getSpectatorTarget() != null) { - player.setSpectatorTarget(null); - } + public static void forceExitRidingState(Player player) { + // 先模拟按下shift键 + player.setSneaking(true); - // 如果玩家正在骑乘载具,让玩家下马 - if (player.getVehicle() != null) { - player.leaveVehicle(); - } + // 如果在旁观者模式下附身了其他实体,先退出附身 + if (player.getGameMode() == GameMode.SPECTATOR && player.getSpectatorTarget() != null) { + player.setSpectatorTarget(null); + } - // 如果玩家身上有乘客,让乘客下来 - if (!player.getPassengers().isEmpty()) { - player.eject(); - } + // 如果玩家正在骑乘载具,让玩家下马 + if (player.getVehicle() != null) { + player.leaveVehicle(); + } - // 恢复正常状态,避免永久潜行 - player.setSneaking(false); - } catch (Exception e) { - if (logger != null) { - logger.warning(String.format("清理玩家 %s 骑乘状态时发生错误: %s", player.getName(), e.getMessage())); - } - // 确保无论如何都恢复sneaking状态 - player.setSneaking(false); + // 如果玩家身上有乘客,让乘客下来 + if (!player.getPassengers().isEmpty()) { + player.eject(); } - } - /** - * 强制退出骑乘/附身状态(无日志版本) - * - * @param player 玩家 - */ - public static void forceExitRidingState(Player player) { - forceExitRidingState(player, null); + // 恢复正常状态,避免永久潜行 + player.setSneaking(false); } /** @@ -67,15 +47,14 @@ public static void forceExitRidingState(Player player) { * 包括唤醒、退出骑乘等 * * @param player 玩家 - * @param logger 日志记录器 */ - public static void prepareForSpectatorMode(Player player, Logger logger) { + public static void prepareForSpectatorMode(Player player) { // 如果玩家在睡觉,先让他离开床 if (player.isSleeping()) { player.wakeup(false); } // 清理骑乘状态 - forceExitRidingState(player, logger); + forceExitRidingState(player); } }