diff --git a/runtime/runtime.cmake b/runtime/runtime.cmake index c714f469..4d646955 100644 --- a/runtime/runtime.cmake +++ b/runtime/runtime.cmake @@ -1282,8 +1282,15 @@ function(psxrecomp_add_runtime_target target) # appearing on the Mods page (and inflate the release packagers' # catalog assertions). This runs before the game's own staging, so # both catalogs land on a clean slate. + # + # Scoped to mods/packages, NOT mods/: both catalogs own only a + # packages/ subtree, while mods/state.toml is USER STATE written at + # runtime (which mods are enabled, with which options). Wiping the + # whole tree silently disabled every enabled mod on every rebuild -- + # 8 MB, widescreen, framerate all reverting off, repeatedly misread + # as the mods themselves regressing. COMMAND ${CMAKE_COMMAND} -E rm -rf - "$/mods" + "$/mods/packages" COMMAND ${CMAKE_COMMAND} -E copy_directory "${PSXRECOMP_ROOT}/mods/builtin" "$/mods" diff --git a/runtime/src/savestate.c b/runtime/src/savestate.c index f8a09e94..1f46273b 100644 --- a/runtime/src/savestate.c +++ b/runtime/src/savestate.c @@ -687,7 +687,16 @@ void savestate_poll(CPUState* cpu, uint32_t resume_pc) { int slot = s_save_pending; char path[600]; uint32_t pc = savestate_resolve_resume_pc(cpu, resume_pc); - if (!savestate_resume_pc_ok(pc)) { + /* hint==0 ALSO defers, even when the resolver found a plausible-looking + * substitute. The substitute chain ends in sticky-BB latches and $ra, + * which pass the sanity check while being the wrong place to resume: + * the first F7 of a session saved such a state, it loaded, ran for + * ~150M instructions off the rails, and died at PC=0 -- poison that + * looks valid at save time and only fails minutes later. Deferring + * reuses the existing retry: the save completes at the next poll where + * a real block-leader PC is published, or fails LOUDLY after the + * timeout instead of writing a corrupt state silently. */ + if (resume_pc == 0u || !savestate_resume_pc_ok(pc)) { /* FMV/present edges often poll with hint=0; wait briefly for a * sticky BB / IRQ latch rather than writing pc=0 poison. */ const double now = savestate_mono_ms();