more u.ustuck issues on save/restore

During a synchronous save operation initiated by the player (or
other trigger for dosave0()), the u.usteed_mid and u.ustuck_mid
values get set by savemonch(), and the monst pointers that
u.ustuck and u.usteed point to are no longer valid, but not
cleared.

The checkpoint operation, which also needs to ensure that
u.ustuck_mid and u.usteed_mid are set, must set them during
the checkpoint, which is okay because the u.usteed and
u.ustuck pointers _are_ valid during a checkpoint operation.

So, we need to distinguish between a save game sequence,
and a checkpoint sequence when writing out the u struct.
This commit is contained in:
nhmall
2026-07-06 14:16:15 -04:00
parent 81ac4deb1e
commit ac151181d2
3 changed files with 27 additions and 7 deletions
+2
View File
@@ -3433,6 +3433,8 @@ set_ustuck(struct monst *mtmp)
disp.botl = TRUE;
u.ustuck = mtmp;
if (u.ustuck_mid)
u.ustuck_mid = 0;
if (!u.ustuck) {
u.uswallow = 0;
u.uswldtim = 0;
+1 -2
View File
@@ -1219,8 +1219,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev)
u.usteed_mid = 0;
} else {
if (mtmp->m_id == u.ustuck_mid) {
set_ustuck(mtmp);
u.ustuck_mid = 0;
set_ustuck(mtmp); /* set_ustuck clears u.ustuck_mid */
}
place_monster(mtmp, mtmp->mx, mtmp->my);
if (mtmp->wormno)
+24 -5
View File
@@ -285,13 +285,32 @@ savegamestate(NHFILE *nhfp)
Sfo_long(nhfp, &svw.wreserve, "wreserve");
Sfo_int32(nhfp, &svw.wtreserved, "wtreserved");
/*
* It is critical to ensure that u.ustuck_mid and u.usteed_mid
* hold current and correct data, in case this is needed by
* recover.
* In a normal save operation initiated by the player,
* the u.ustuck_mid and u.usteed_mid were already set
* by savemonchn() called from savelev_core(). Under
* that operation, u.ustuck and u.usteed pointers no longer
* point to valid locations here. Their non-zero values serve
* only to flag that they are were set, but the pointers
* must not be dereferenced.
*/
u.ustuck_mid = (u.ustuck) ? u.ustuck->m_id : 0;
u.usteed_mid = (u.usteed) ? u.usteed->m_id : 0;
if (program_state.in_checkpoint) {
/*
* It is critical to ensure that u.ustuck_mid and u.usteed_mid
* hold current and correct data, in case this is needed by
* recover. The pointers, if set, are still pointing at
* valid data during a checkpoint operation, unlike during
* a synchronized save operation.
*/
u.ustuck_mid = (u.ustuck) ? u.ustuck->m_id : 0;
u.usteed_mid = (u.usteed) ? u.usteed->m_id : 0;
}
Sfo_you(nhfp, &u, "gamestate-you");
/* clear the in-memory value of these, now that they have been
* successfully written out.
*/
u.ustuck_mid = 0;
u.usteed_mid = 0;
Sfo_char(nhfp, yyyymmddhhmmss(ubirthday), "gamestate-ubirthday", 14);
Sfo_long(nhfp, &urealtime.realtime, "gamestate-realtime");
Sfo_char(nhfp, yyyymmddhhmmss(urealtime.start_timing), "gamestate-start_timing", 14);