Replays: fix ghosts not being freed if Time Attacking and letting the map exit without manually returning to the menu

- Fixes a very specific crash
- Record a Time Attack
- Let the map exit naturally
  - I tested by FALLING OUT of a Sealed Star
- Start recording another Time Attack
  - I tested by going to the same map again
- Result
  - One of three possibilities
  - Z_Free: wrong id
  - SIGSEGV
  - Game freezes and hangs forever
- I also wrote detailed comments in M_EndModeAttackRun so
  you know what it's supposed to be doing
This commit is contained in:
James R 2024-03-10 06:46:28 -07:00
parent 4de4c9e57d
commit 032c5bb27c

View file

@ -54,12 +54,41 @@ menu_t PAUSE_PlaybackMenuDef = {
void M_EndModeAttackRun(void)
{
if (demo.playback)
// End recording / playback.
// Why not check demo.recording?
// Because for recording, this may be called from G_AfterIntermission.
// And before this function is called, G_SaveDemo is called, which sets demo.recording to false.
// Don't need to check demo.playback; G_CheckDemoStatus is safe to call even outside of demos.
// Check modeattacking because this function is recursively called (read on for an explanation).
if (modeattacking)
{
G_CheckDemoStatus(); // Cancel recording
return;
// This must be called for both playback and
// recording, because it both finishes playback and
// frees ghost data.
G_CheckDemoStatus();
// What does G_CheckDemoStatus do? Here's the answer!
// Playback:
// - Clears everything, including demo state and modeattacking.
// - It then calls the current function (M_EndModeAttackRun) AGAIN (after everything was cleared), so return.
if (!modeattacking)
return;
// Recording:
// - Only saves the demo and clears the demo state.
// - Now we need to clear the rest of the gamestate ourself!
}
// Playback: modeattacking is always false, so calling this returns to the menu.
// Recording: modeattacking is still true and this function call preserves that.
Command_ExitGame_f();
if (!modeattacking)
return;
// The rest of this is relevant for recording ONLY.
if (nextmapoverride != 0)
{
M_StartMessage(
@ -76,13 +105,10 @@ void M_EndModeAttackRun(void)
);
}
Command_ExitGame_f(); // Clear a bunch of state
if (!modeattacking)
return;
modeattacking = ATTACKING_NONE; // Kept until now because of Command_ExitGame_f
// Command_ExitGame_f didn't clear this, so now we do.
modeattacking = ATTACKING_NONE;
// Return to the menu.
if (demo.attract == DEMO_ATTRACT_TITLE)
{
D_SetDeferredStartTitle(true);