fix(load): the respawn checkpoint follows ServerDoneLoadingAllObjects on every load

Live sent PlayerReachedRespawnCheckpoint right after
ServerDoneLoadingAllObjects on 143 of 157 captured loads, with a
rotation: the spawn point the player arrived at, or a checkpoint they
had reached before. DLU sent it before constructing the zone's objects,
only when a checkpoint was saved for the zone, and always unrotated.

It now goes right after ServerDoneLoadingAllObjects on every load: the
saved checkpoint when there is one (DLU saves no rotation for it, so
that one stays unrotated), otherwise the position and facing the
player loaded in at. Inferred: that the loaded-in spot matches live's
spawn point choice (live's is the spawn point object, a few tenths of
a unit from the player's start).

Check: log in fresh to a zone, die before touching any checkpoint and
respawn: you come back where you arrived, facing the same way; reach
a checkpoint, change zones and come back, die: you respawn at that
checkpoint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-29 03:29:39 -05:00
parent a25eb34d66
commit 87ce8e3e45
4 changed files with 53 additions and 11 deletions

View File

@@ -1,4 +1,5 @@
#include "ZoneMessages.h"
#include "MovementMessages.h"
#include "BitStreamUtils.h"
#include "CDClientManager.h"
@@ -35,6 +36,19 @@ namespace GameMessages {
return bitStream.Read(playerID);
}
void SendDoneLoading(const LWOOBJID player, const NiPoint3& savedCheckpoint, const NiPoint3& spawnPosition, const NiQuaternion& spawnRotation, const SystemAddress& sysAddr) {
ServerDoneLoadingAllObjects doneLoading;
doneLoading.target = player;
doneLoading.SendToClient(sysAddr);
PlayerReachedRespawnCheckpoint checkpoint;
checkpoint.target = player;
const bool hasSavedCheckpoint = savedCheckpoint != NiPoint3Constant::ZERO;
checkpoint.pos = hasSavedCheckpoint ? savedCheckpoint : spawnPosition;
checkpoint.rot = hasSavedCheckpoint ? QuatUtils::IDENTITY : spawnRotation;
checkpoint.SendToClient(sysAddr);
}
void SendPlayerReady(const LWOOBJID player, const LWOOBJID zoneControl, const SystemAddress& sysAddr) {
PlayerReady playerReady;
playerReady.target = player;