Handle corrupted coroutine state better
This commit is contained in:
41
src/sm_82.c
41
src/sm_82.c
@@ -605,15 +605,24 @@ static Func_V_Coroutine *const kGameStateFuncs[45] = {
|
|||||||
GameState_44_TransitionFromDemo,
|
GameState_44_TransitionFromDemo,
|
||||||
};
|
};
|
||||||
|
|
||||||
CoroutineRet RunGameStateTrampoline_Async(void) {
|
|
||||||
// printf("gamestate %d\n", game_state);
|
|
||||||
return kGameStateFuncs[(uint16)(2 * (uint8)game_state) >> 1]();
|
|
||||||
}
|
|
||||||
|
|
||||||
CoroutineRet RunOneFrameOfGameInner(void) {
|
CoroutineRet RunOneFrameOfGameInner(void) {
|
||||||
COROUTINE_BEGIN(coroutine_state_0, 1: case 2: case 3);
|
int st = coroutine_state_0;
|
||||||
COROUTINE_AWAIT_ONLY(Vector_RESET_Async())
|
// This uses manual coroutine handling because of the
|
||||||
COROUTINE_MANUAL_POS(0);
|
// kGameStateFuncs[game_state]() thing, we need to make
|
||||||
|
// sure we resume at the same position even if it changes
|
||||||
|
// behind our back.
|
||||||
|
if (st >= 1 && st <= 3) {
|
||||||
|
COROUTINE_AWAIT_ONLY(Vector_RESET_Async())
|
||||||
|
} else if (st >= 10) {
|
||||||
|
goto RESUME_AT_SWITCH;
|
||||||
|
} else if (st != 0) {
|
||||||
|
Die("Incorrect coroutine_state_0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure these are reset to a known state.
|
||||||
|
// There was a bug where these would have the wrong value.
|
||||||
|
coroutine_state_1 = coroutine_state_2 = coroutine_state_3 = coroutine_state_4 = 0;
|
||||||
|
|
||||||
ReadJoypadInputs();
|
ReadJoypadInputs();
|
||||||
HdmaObjectHandler();
|
HdmaObjectHandler();
|
||||||
NextRandom();
|
NextRandom();
|
||||||
@@ -622,11 +631,23 @@ CoroutineRet RunOneFrameOfGameInner(void) {
|
|||||||
nmi_copy_samus_halves = 0;
|
nmi_copy_samus_halves = 0;
|
||||||
nmi_copy_samus_top_half_src = 0;
|
nmi_copy_samus_top_half_src = 0;
|
||||||
nmi_copy_samus_bottom_half_src = 0;
|
nmi_copy_samus_bottom_half_src = 0;
|
||||||
COROUTINE_AWAIT(4, RunGameStateTrampoline_Async());
|
|
||||||
|
coroutine_state_0 = st = game_state + 10;
|
||||||
|
RESUME_AT_SWITCH:
|
||||||
|
COROUTINE_AWAIT_ONLY(kGameStateFuncs[st - 10]());
|
||||||
|
|
||||||
HandleSoundEffects();
|
HandleSoundEffects();
|
||||||
ClearUnusedOam();
|
ClearUnusedOam();
|
||||||
ShowSpareCpu();
|
ShowSpareCpu();
|
||||||
COROUTINE_END(0);
|
|
||||||
|
if (coroutine_state_1 | coroutine_state_2 | coroutine_state_3 | coroutine_state_4) {
|
||||||
|
printf("Coroutine state: %d, %d, %d, %d\n",
|
||||||
|
coroutine_state_1, coroutine_state_2, coroutine_state_3, coroutine_state_4);
|
||||||
|
Warning("Coroutine State is broken!");
|
||||||
|
}
|
||||||
|
|
||||||
|
coroutine_state_0 = 0;
|
||||||
|
return kCoroutineNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunOneFrameOfGame(void) { // 0x828948
|
void RunOneFrameOfGame(void) { // 0x828948
|
||||||
|
|||||||
10
src/sm_rtl.c
10
src/sm_rtl.c
@@ -465,6 +465,16 @@ void RtlSaveLoad(int cmd, int slot) {
|
|||||||
RtlApuUnlock();
|
RtlApuUnlock();
|
||||||
RtlSynchronizeWholeState();
|
RtlSynchronizeWholeState();
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
|
if (coroutine_state_0 | coroutine_state_1 | coroutine_state_2 | coroutine_state_3 | coroutine_state_4) {
|
||||||
|
printf("Coroutine state: %d, %d, %d, %d, %d\n",
|
||||||
|
coroutine_state_0, coroutine_state_1, coroutine_state_2, coroutine_state_3, coroutine_state_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Earlier versions used coroutine_state_0 differently
|
||||||
|
if (coroutine_state_0 == 4)
|
||||||
|
coroutine_state_0 = 10 + game_state;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
RtlSaveSnapshot(name, false);
|
RtlSaveSnapshot(name, false);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user