Skip to content

Commit 64b04a6

Browse files
优化一下peek的命令提示,顺便修复卡观察者的bug
1 parent 04d6723 commit 64b04a6

5 files changed

Lines changed: 216 additions & 96 deletions

File tree

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>ict.minesunshineone</groupId>
88
<artifactId>peek</artifactId>
9-
<version>3.2</version>
9+
<version>3.3</version>
1010

1111
<properties>
1212
<maven.compiler.release>17</maven.compiler.release>

src/main/java/ict/minesunshineone/peek/command/PeekCommand.java

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
3535
}
3636

3737
if (args.length == 0) {
38-
plugin.getMessages().send(player, "usage");
38+
sendHelp(player);
3939
return true;
4040
}
4141

@@ -180,6 +180,63 @@ private boolean handleRandomPeek(Player player) {
180180
return true;
181181
}
182182

183+
private void sendHelp(Player player) {
184+
player.sendMessage(net.kyori.adventure.text.Component.empty());
185+
player.sendMessage(net.kyori.adventure.text.Component
186+
.text("═══════ ", net.kyori.adventure.text.format.NamedTextColor.DARK_GRAY)
187+
.append(net.kyori.adventure.text.Component.text("观察指令帮助",
188+
net.kyori.adventure.text.format.NamedTextColor.GREEN,
189+
net.kyori.adventure.text.format.TextDecoration.BOLD))
190+
.append(net.kyori.adventure.text.Component.text(" ═══════",
191+
net.kyori.adventure.text.format.NamedTextColor.DARK_GRAY)));
192+
player.sendMessage(net.kyori.adventure.text.Component.empty());
193+
194+
player.sendMessage(
195+
net.kyori.adventure.text.Component.text("▸ 观察功能", net.kyori.adventure.text.format.NamedTextColor.AQUA,
196+
net.kyori.adventure.text.format.TextDecoration.BOLD));
197+
sendCmd(player, "/peek <玩家名>", "观察指定玩家的视角");
198+
sendCmd(player, "/peek random", "随机观察一位在线玩家");
199+
sendCmd(player, "/peek self", "原地peek自己");
200+
sendCmd(player, "/peek exit", "退出观察模式");
201+
202+
player.sendMessage(net.kyori.adventure.text.Component.empty());
203+
player.sendMessage(net.kyori.adventure.text.Component.text("▸ 隐私与统计",
204+
net.kyori.adventure.text.format.NamedTextColor.YELLOW,
205+
net.kyori.adventure.text.format.TextDecoration.BOLD));
206+
sendCmd(player, "/peek privacy", "切换隐私模式");
207+
sendCmd(player, "/peek accept", "接受观察请求");
208+
sendCmd(player, "/peek deny", "拒绝观察请求");
209+
if (player.hasPermission("peek.stats")) {
210+
sendCmd(player, "/peek stats", "查看观察统计数据");
211+
}
212+
213+
player.sendMessage(net.kyori.adventure.text.Component.empty());
214+
player.sendMessage(
215+
net.kyori.adventure.text.Component.text("提示: ", net.kyori.adventure.text.format.NamedTextColor.GRAY)
216+
.append(net.kyori.adventure.text.Component.text("点击命令可快速填入聊天框",
217+
net.kyori.adventure.text.format.NamedTextColor.DARK_GRAY,
218+
net.kyori.adventure.text.format.TextDecoration.ITALIC)));
219+
player.sendMessage(net.kyori.adventure.text.Component.empty());
220+
}
221+
222+
private void sendCmd(Player player, String cmd, String desc) {
223+
net.kyori.adventure.text.Component cmdComponent = net.kyori.adventure.text.Component
224+
.text(" " + cmd, net.kyori.adventure.text.format.NamedTextColor.GREEN)
225+
.hoverEvent(net.kyori.adventure.text.event.HoverEvent.showText(
226+
net.kyori.adventure.text.Component
227+
.text(desc, net.kyori.adventure.text.format.NamedTextColor.WHITE)
228+
.append(net.kyori.adventure.text.Component.newline())
229+
.append(net.kyori.adventure.text.Component.text("点击填入命令",
230+
net.kyori.adventure.text.format.NamedTextColor.GRAY,
231+
net.kyori.adventure.text.format.TextDecoration.ITALIC))))
232+
.clickEvent(net.kyori.adventure.text.event.ClickEvent.suggestCommand(cmd.split("<")[0].trim() + " "));
233+
234+
net.kyori.adventure.text.Component descComponent = net.kyori.adventure.text.Component.text(" - " + desc,
235+
net.kyori.adventure.text.format.NamedTextColor.GRAY);
236+
237+
player.sendMessage(cmdComponent.append(descComponent));
238+
}
239+
183240
@Override
184241
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
185242
if (!(sender instanceof Player)) {

src/main/java/ict/minesunshineone/peek/handler/PeekStateHandler.java

Lines changed: 56 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import ict.minesunshineone.peek.PeekPlugin;
1515
import ict.minesunshineone.peek.data.PeekData;
16+
import ict.minesunshineone.peek.util.PlayerStateUtil;
1617

1718
/**
1819
* 核心 Peek 状态管理器
@@ -22,7 +23,7 @@ public class PeekStateHandler {
2223

2324
private final PeekPlugin plugin;
2425
private final Map<UUID, PeekData> activePeeks = new HashMap<>();
25-
26+
2627
// 委托的处理器
2728
private final BossBarHandler bossBarHandler;
2829
private final RangeChecker rangeChecker;
@@ -66,8 +67,7 @@ public void startPeek(Player peeker, Player target) {
6667
peeker.getHealth(),
6768
peeker.getFoodLevel(),
6869
peeker.getSaturation(),
69-
peeker.getActivePotionEffects()
70-
);
70+
peeker.getActivePotionEffects());
7171

7272
activePeeks.put(peeker.getUniqueId(), data);
7373
plugin.getStateManager().savePlayerState(peeker, data);
@@ -81,7 +81,7 @@ public void startPeek(Player peeker, Player target) {
8181

8282
// 发送消息给观察者
8383
plugin.getMessages().send(peeker, "peek-start", "player", target.getName());
84-
84+
8585
// 只有非静默模式才通知目标
8686
if (!silentPeek) {
8787
plugin.getMessages().send(target, "being-peeked", "player", peeker.getName());
@@ -120,10 +120,10 @@ public void startSelfPeek(Player peeker) {
120120

121121
try {
122122
logDebug("Starting self peek: %s", peeker.getName());
123-
123+
124124
// 保存当前位置作为原始位置
125125
Location originalLocation = peeker.getLocation().clone();
126-
126+
127127
// 创建特殊的 PeekData,目标设为自己
128128
PeekData data = new PeekData(
129129
originalLocation,
@@ -133,16 +133,15 @@ public void startSelfPeek(Player peeker) {
133133
peeker.getHealth(),
134134
peeker.getFoodLevel(),
135135
peeker.getSaturation(),
136-
peeker.getActivePotionEffects()
137-
);
136+
peeker.getActivePotionEffects());
138137

139138
activePeeks.put(peeker.getUniqueId(), data);
140139
plugin.getStateManager().savePlayerState(peeker, data);
141140
plugin.getStatisticsManager().recordPeekStart(peeker, peeker); // 统计中目标也是自己
142141

143142
// 设置为观察者模式但不传送
144143
setSelfPeekGameMode(peeker);
145-
144+
146145
// 发送消息
147146
plugin.getMessages().send(peeker, "self-peek-start");
148147

@@ -153,15 +152,16 @@ public void startSelfPeek(Player peeker) {
153152
// 创建 BossBar 并启动自我观察距离检查器
154153
bossBarHandler.createSelfPeekBossBar(peeker, plugin.getMessages().get("self-peek-origin", "原点"));
155154
startSelfRangeChecker(peeker, originalLocation);
156-
155+
157156
logDebug("Self peek started successfully for player: %s", peeker.getName());
158-
157+
159158
} catch (Exception e) {
160-
plugin.getLogger().warning(String.format("启动自我观察时发生错误,玩家: %s,错误: %s", peeker.getName(), e.getMessage()));
159+
plugin.getLogger()
160+
.warning(String.format("启动自我观察时发生错误,玩家: %s,错误: %s", peeker.getName(), e.getMessage()));
161161
if (plugin.getConfig().getBoolean("debug", false)) {
162162
e.printStackTrace();
163163
}
164-
164+
165165
// 清理可能的残留状态
166166
activePeeks.remove(peeker.getUniqueId());
167167
// 通知玩家发生错误
@@ -220,11 +220,11 @@ public void endPeek(Player peeker, boolean shouldRestore) {
220220
if (peeker.isOnline()) {
221221
plugin.getMessages().send(peeker, "peek-end");
222222
}
223-
223+
224224
// 检查是否是自我观察模式
225225
boolean isSelfPeek = target != null && target.getUniqueId().equals(peeker.getUniqueId());
226226
boolean silentPeek = peeker.isOnline() && plugin.getTargetHandler().shouldSilentPeek(peeker);
227-
227+
228228
// 非自我观察且非静默模式才通知目标
229229
if (target != null && target.isOnline() && !isSelfPeek && !silentPeek) {
230230
plugin.getMessages().send(target, "peek-end-target", "player", peeker.getName());
@@ -249,23 +249,13 @@ private void teleportAndSetGameMode(Player peeker, Player target) {
249249
// 先切换游戏模式
250250
plugin.getServer().getRegionScheduler().run(plugin, peeker.getLocation(), task -> {
251251
try {
252-
// 如果玩家在睡觉,先让他离开床
253-
if (peeker.isSleeping()) {
254-
peeker.wakeup(false);
255-
}
256-
257-
// 传送之前先设置为蹲下
258-
peeker.setSneaking(true);
259-
260-
// 如果玩家在附身状态,先退出附身
261-
if (peeker.getGameMode() == GameMode.SPECTATOR && peeker.getSpectatorTarget() != null) {
262-
peeker.setSpectatorTarget(null);
263-
}
252+
// 清理骑乘状态,准备进入旁观者模式
253+
PlayerStateUtil.prepareForSpectatorMode(peeker, plugin.getLogger());
264254

265255
// 设置为旁观模式
266256
peeker.setGameMode(GameMode.SPECTATOR);
267257

268-
// 等待1 tick后再传送
258+
// 等待2 tick后再传送
269259
plugin.getServer().getRegionScheduler().runDelayed(plugin, peeker.getLocation(), delayedTask -> {
270260
peeker.teleportAsync(target.getLocation(), TeleportCause.PLUGIN).thenAccept(success -> {
271261
if (!success) {
@@ -282,6 +272,7 @@ private void teleportAndSetGameMode(Player peeker, Player target) {
282272
}, 2L); // 2 tick 延迟
283273
} catch (Exception e) {
284274
plugin.getLogger().warning(String.format("为玩家 %s 切换游戏模式时发生错误", peeker.getName()));
275+
peeker.setSneaking(false); // 确保异常时也恢复状态
285276
endPeek(peeker);
286277
}
287278
});
@@ -303,69 +294,63 @@ private void setSelfPeekGameMode(Player peeker) {
303294
return;
304295
}
305296

306-
if (peeker.isSleeping()) {
307-
peeker.wakeup(false);
308-
}
309-
310-
if (peeker.getGameMode() == GameMode.SPECTATOR && peeker.getSpectatorTarget() != null) {
311-
peeker.setSpectatorTarget(null);
312-
}
297+
// 清理骑乘状态,准备进入旁观者模式
298+
PlayerStateUtil.prepareForSpectatorMode(peeker, plugin.getLogger());
313299

314300
peeker.setGameMode(GameMode.SPECTATOR);
315-
301+
316302
logDebug("Successfully set self peek game mode for player: %s", peeker.getName());
317303
} catch (Exception e) {
318304
plugin.getLogger().warning(String.format("为玩家 %s 设置自我观察模式时发生错误: %s", peeker.getName(), e.getMessage()));
319305
if (plugin.getConfig().getBoolean("debug", false)) {
320306
e.printStackTrace();
321307
}
308+
peeker.setSneaking(false); // 确保异常时也恢复状态
322309
endPeek(peeker);
323310
}
324311
});
325312
}
326313

327314
private void startNormalRangeChecker(Player peeker, Player target) {
328315
rangeChecker.startRangeChecker(peeker, target,
329-
// 超出范围时
330-
() -> {
331-
plugin.getMessages().send(peeker, "range-exceeded");
332-
endPeek(peeker);
333-
},
334-
// 目标离线时
335-
() -> endPeek(peeker),
336-
// 距离更新时
337-
(distance) -> {
338-
PeekData data = activePeeks.get(peeker.getUniqueId());
339-
bossBarHandler.updateDistanceBossBar(peeker, distance, data);
340-
},
341-
// 不同世界时
342-
() -> {
343-
plugin.getMessages().send(peeker, "target-in-different-world");
344-
teleportAndSetGameMode(peeker, target);
345-
}
346-
);
316+
// 超出范围时
317+
() -> {
318+
plugin.getMessages().send(peeker, "range-exceeded");
319+
endPeek(peeker);
320+
},
321+
// 目标离线时
322+
() -> endPeek(peeker),
323+
// 距离更新时
324+
(distance) -> {
325+
PeekData data = activePeeks.get(peeker.getUniqueId());
326+
bossBarHandler.updateDistanceBossBar(peeker, distance, data);
327+
},
328+
// 不同世界时
329+
() -> {
330+
plugin.getMessages().send(peeker, "target-in-different-world");
331+
teleportAndSetGameMode(peeker, target);
332+
});
347333
}
348334

349335
private void startSelfRangeChecker(Player peeker, Location originalLocation) {
350336
String selfPeekLabel = plugin.getMessages().get("self-peek-origin", "原点");
351337
rangeChecker.startSelfRangeChecker(peeker, originalLocation,
352-
// 获取 Peek 数据
353-
() -> activePeeks.get(peeker.getUniqueId()),
354-
// 超出自我观察范围时
355-
() -> {
356-
plugin.getMessages().send(peeker, "self-peek-range-exceeded");
357-
endPeek(peeker);
358-
},
359-
// 世界改变时
360-
() -> {
361-
plugin.getMessages().send(peeker, "self-peek-world-changed");
362-
endPeek(peeker);
363-
},
364-
// 距离更新时(用于更新 BossBar)
365-
(distance) -> bossBarHandler.updateDistanceBossBar(peeker, distance, selfPeekLabel),
366-
// 发生错误时
367-
() -> endPeek(peeker)
368-
);
338+
// 获取 Peek 数据
339+
() -> activePeeks.get(peeker.getUniqueId()),
340+
// 超出自我观察范围时
341+
() -> {
342+
plugin.getMessages().send(peeker, "self-peek-range-exceeded");
343+
endPeek(peeker);
344+
},
345+
// 世界改变时
346+
() -> {
347+
plugin.getMessages().send(peeker, "self-peek-world-changed");
348+
endPeek(peeker);
349+
},
350+
// 距离更新时(用于更新 BossBar)
351+
(distance) -> bossBarHandler.updateDistanceBossBar(peeker, distance, selfPeekLabel),
352+
// 发生错误时
353+
() -> endPeek(peeker));
369354
}
370355

371356
private void stopRangeCheckerAndBossBar(Player peeker) {

0 commit comments

Comments
 (0)