88import org .bukkit .GameMode ;
99import org .bukkit .Location ;
1010import org .bukkit .Sound ;
11+ import org .bukkit .attribute .Attribute ;
12+ import org .bukkit .attribute .AttributeInstance ;
1113import org .bukkit .entity .Player ;
14+ import org .bukkit .event .player .PlayerTeleportEvent .TeleportCause ;
1215import org .bukkit .util .Vector ;
1316
1417import ict .minesunshineone .peek .PeekPlugin ;
@@ -263,7 +266,7 @@ private void teleportAndSetGameMode(Player peeker, Player target) {
263266
264267 // 等待1 tick后再传送
265268 plugin .getServer ().getRegionScheduler ().runDelayed (plugin , peeker .getLocation (), delayedTask -> {
266- peeker .teleportAsync (target .getLocation ()).thenAccept (success -> {
269+ peeker .teleportAsync (target .getLocation (), TeleportCause . PLUGIN ).thenAccept (success -> {
267270 if (!success ) {
268271 plugin .getMessages ().send (peeker , "teleport-failed" );
269272 endPeek (peeker );
@@ -290,58 +293,102 @@ public void restorePlayerState(Player peeker, PeekData data) {
290293 // 在传送前先清除动量
291294 peeker .setVelocity (new Vector (0 , 0 , 0 ));
292295
293- peeker .teleportAsync (data .getOriginalLocation ()).thenAccept (success -> {
296+ peeker .teleportAsync (data .getOriginalLocation (), TeleportCause . PLUGIN ).thenAccept (success -> {
294297 if (success ) {
295298 // 传送成功后再改变游戏模式
296299 plugin .getServer ().getRegionScheduler ().run (plugin , data .getOriginalLocation (), modeTask -> {
297- // 再次确保动量为0
298- peeker .setVelocity (new Vector (0 , 0 , 0 ));
299-
300- peeker .setGameMode (data .getOriginalGameMode ());
301- // 恢复新增状态
302- peeker .setHealth (Math .min (data .getHealth (), 20 ));
303- peeker .setFoodLevel (data .getFoodLevel ());
304- peeker .setSaturation (data .getSaturation ());
305-
306- // 清除现有效果并应用保存的效果
307- peeker .getActivePotionEffects ().forEach (effect
308- -> peeker .removePotionEffect (effect .getType ()));
309- data .getPotionEffects ().forEach (effect
310- -> peeker .addPotionEffect (effect ));
300+ applyRestoredState (peeker , data );
311301 });
312302 } else {
313- plugin .getLogger ().warning (String .format (
314- "无法将玩家 %s 传送回原位置,正在尝试传送到重生点" ,
315- peeker .getName ()
316- ));
317-
318- Location spawnLoc = peeker .getBedSpawnLocation () != null
319- ? peeker .getBedSpawnLocation ()
320- : peeker .getWorld ().getSpawnLocation ();
321-
322- if (spawnLoc != null ) {
323- plugin .getServer ().getRegionScheduler ().run (plugin , spawnLoc , spawnTask -> {
324- peeker .teleportAsync (spawnLoc ).thenAccept (spawnSuccess -> {
325- if (spawnSuccess ) {
326- // 传送到重生点成功后再改变游戏模式
327- plugin .getServer ().getRegionScheduler ().run (plugin , spawnLoc , modeTask -> {
328- peeker .setGameMode (data .getOriginalGameMode ());
329- });
330- } else {
331- plugin .getLogger ().severe (String .format (
332- "无法将玩家 %s 传送到任何安全位置" ,
333- peeker .getName ()
334- ));
335- }
336- });
303+ handleTeleportFailure (peeker , data );
304+ }
305+ });
306+ });
307+ }
308+
309+ private void handleTeleportFailure (Player peeker , PeekData data ) {
310+ plugin .getLogger ().warning (String .format (
311+ "无法将玩家 %s 传送回原位置,正在尝试传送到重生点" ,
312+ peeker .getName ()
313+ ));
314+
315+ Location spawnLoc = resolveSpawnLocation (peeker );
316+
317+ if (spawnLoc != null ) {
318+ plugin .getServer ().getRegionScheduler ().run (plugin , spawnLoc , spawnTask -> {
319+ peeker .teleportAsync (spawnLoc , TeleportCause .PLUGIN ).thenAccept (spawnSuccess -> {
320+ if (spawnSuccess ) {
321+ plugin .getServer ().getRegionScheduler ().run (plugin , spawnLoc , modeTask -> {
322+ applyRestoredState (peeker , data );
337323 });
324+ } else {
325+ plugin .getLogger ().severe (String .format (
326+ "无法将玩家 %s 传送到任何安全位置" ,
327+ peeker .getName ()
328+ ));
329+ forceStateRestoreWithoutTeleport (peeker , data );
338330 }
339- plugin .getMessages ().send (peeker , "teleport-failed" );
340- }
331+ });
341332 });
333+ } else {
334+ plugin .getLogger ().severe (String .format (
335+ "未找到可用的重生点,强制恢复玩家 %s 的状态" ,
336+ peeker .getName ()
337+ ));
338+ forceStateRestoreWithoutTeleport (peeker , data );
339+ }
340+
341+ plugin .getMessages ().send (peeker , "teleport-failed" );
342+ }
343+
344+ private Location resolveSpawnLocation (Player peeker ) {
345+ Location respawnLocation = peeker .getRespawnLocation ();
346+ if (respawnLocation != null ) {
347+ return respawnLocation ;
348+ }
349+
350+ if (peeker .getWorld () != null ) {
351+ return peeker .getWorld ().getSpawnLocation ();
352+ }
353+
354+ return plugin .getServer ().getWorlds ().isEmpty ()
355+ ? null
356+ : plugin .getServer ().getWorlds ().get (0 ).getSpawnLocation ();
357+ }
358+
359+ private void forceStateRestoreWithoutTeleport (Player peeker , PeekData data ) {
360+ plugin .getServer ().getRegionScheduler ().run (plugin , peeker .getLocation (), modeTask -> {
361+ applyRestoredState (peeker , data );
342362 });
343363 }
344364
365+ private void applyRestoredState (Player peeker , PeekData data ) {
366+ // 再次确保动量为0
367+ peeker .setVelocity (new Vector (0 , 0 , 0 ));
368+
369+ // 确保观察者附身关系被清除
370+ if (peeker .getGameMode () == GameMode .SPECTATOR && peeker .getSpectatorTarget () != null ) {
371+ peeker .setSpectatorTarget (null );
372+ }
373+
374+ peeker .setGameMode (data .getOriginalGameMode ());
375+ double maxHealth = getMaxHealth (peeker );
376+ peeker .setHealth (Math .min (data .getHealth (), maxHealth ));
377+ peeker .setFoodLevel (data .getFoodLevel ());
378+ peeker .setSaturation (data .getSaturation ());
379+
380+ // 清除现有效果并应用保存的效果
381+ peeker .getActivePotionEffects ().forEach (effect
382+ -> peeker .removePotionEffect (effect .getType ()));
383+ data .getPotionEffects ().forEach (effect
384+ -> peeker .addPotionEffect (effect ));
385+ }
386+
387+ private double getMaxHealth (Player peeker ) {
388+ AttributeInstance instance = peeker .getAttribute (Attribute .GENERIC_MAX_HEALTH );
389+ return instance != null ? instance .getValue () : 20.0D ;
390+ }
391+
345392 public Map <UUID , PeekData > getActivePeeks () {
346393 return Collections .unmodifiableMap (activePeeks );
347394 }
0 commit comments