From fc3128df1268d91f2a2e4b78ca9e2d9efd14c5aa Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 30 Apr 2024 22:54:42 -0500 Subject: [PATCH] Always exit TryRunTics loop early if deferring gamestate change Calls to F_ContinueCredits and D_StartTitle, even if deferred, change the current gamestate. However, the tic loop in TryRunTics may still have a couple tics to execute to catch up to current time, and as a consequence G_Ticker may execute game logic while the current state is not GS_LEVEL or equivalent. As a result, it is highly likely for the game to crash. This adds deferred credits start to the tic loop, and exits that loop if either title or credits are supposed to start after the current iteration, fixing this crash scenario. Fixes KartKrew/Kart#1185 --- src/d_clisrv.c | 12 ++++++++++++ src/d_netcmd.c | 2 +- src/g_demo.cpp | 2 +- src/k_credits.cpp | 14 ++++++++++++++ src/k_credits.h | 4 ++++ 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index a4a778bec..f9a3e3e1b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -52,6 +52,7 @@ #include "stun.h" // SRB2Kart +#include "k_credits.h" #include "k_kart.h" #include "k_battle.h" #include "k_pwrlv.h" @@ -6146,6 +6147,11 @@ boolean TryRunTics(tic_t realtics) ps_tictime = I_GetPreciseTime() - ps_tictime; + if (F_IsDeferredContinueCredits()) + { + F_ContinueCredits(); + } + if (D_IsDeferredStartTitle()) { D_StartTitle(); @@ -6156,6 +6162,12 @@ boolean TryRunTics(tic_t realtics) { break; } + + // if we're no longer in a level state, just exit + if (!G_GamestateUsesLevel()) + { + break; + } } } else diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7a9d1b403..2f15f2840 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -6390,7 +6390,7 @@ void Command_ExitGame_f(void) // YES, this is where demo.attract gets cleared! if (demo.attract == DEMO_ATTRACT_CREDITS) { - F_ContinueCredits(); // <-- clears demo.attract + F_DeferContinueCredits(); // <-- clears demo.attract } else if (restoreMenu == NULL) // this is true for attract demos too! { diff --git a/src/g_demo.cpp b/src/g_demo.cpp index a22595aad..4e0bfd437 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -4052,7 +4052,7 @@ boolean G_CheckDemoStatus(void) else if (wasmodeattacking) M_EndModeAttackRun(); else if (demo.attract == DEMO_ATTRACT_CREDITS) - F_ContinueCredits(); + F_DeferContinueCredits(); else D_SetDeferredStartTitle(true); } diff --git a/src/k_credits.cpp b/src/k_credits.cpp index 36c364d1d..d867e2b6e 100644 --- a/src/k_credits.cpp +++ b/src/k_credits.cpp @@ -126,6 +126,8 @@ constexpr const fixed_t kScrollFactor = FRACUNIT * 7 / 8; constexpr const int kSkipSpeed = 8; constexpr const int kScrollSkipSpeed = 4; +static bool g_deferred_continue_credits = false; + void F_LoadCreditsDefinitions(void) { // Load credits definitions from bios.pk3 @@ -448,8 +450,20 @@ static void F_CreditsNextSlide(void) F_InitCreditsSlide(); } +void F_DeferContinueCredits(void) +{ + g_deferred_continue_credits = true; + demo.attract = DEMO_ATTRACT_OFF; +} + +boolean F_IsDeferredContinueCredits(void) +{ + return g_deferred_continue_credits; +} + void F_ContinueCredits(void) { + g_deferred_continue_credits = false; G_SetGamestate(GS_CREDITS); F_CreditsReset(); demo.attract = DEMO_ATTRACT_OFF; diff --git a/src/k_credits.h b/src/k_credits.h index fc00c41cf..6e080dc9c 100644 --- a/src/k_credits.h +++ b/src/k_credits.h @@ -26,6 +26,10 @@ void F_CreditsReset(void); void F_StartCredits(void); +void F_DeferContinueCredits(void); + +boolean F_IsDeferredContinueCredits(void); + void F_ContinueCredits(void); void F_TickCreditsDemoExit(void);