More level transition synchronization rewrites

I believe this fixes #51
This commit is contained in:
MysterD 2020-09-11 15:32:05 -07:00
parent 791423ff98
commit 163527401e
5 changed files with 135 additions and 75 deletions

View file

@ -49,6 +49,7 @@
u8 gControlledWarp = 0;
u8 gReceiveWarp = 0;
struct WarpDest gReceiveWarpDest = { 0 };
extern s8 sReceivedLoadedActNum;
#ifdef VERSION_JP
const char *credits01[] = { "1GAME DIRECTOR", "SHIGERU MIYAMOTO" };
@ -986,7 +987,7 @@ void basic_update(UNUSED s16 *arg) {
}
}
static void check_for_received_warp(void) {
static void check_received_warp(void) {
if (!gReceiveWarp) { return; }
gReceiveWarp = FALSE;
sWarpDest = gReceiveWarpDest;
@ -995,8 +996,7 @@ static void check_for_received_warp(void) {
// force well behaved state
extern s16 gMenuMode;
reset_dialog_render_state();
level_set_transition(0, 0);
sTransitionUpdate = NULL;
level_set_transition(1, 0);
gMenuMode = -1;
gPauseScreenMode = 1;
gSaveOptSelectIndex = 0;
@ -1007,6 +1007,15 @@ static void check_for_received_warp(void) {
set_play_mode((sWarpDest.type == WARP_TYPE_CHANGE_LEVEL)
? PLAY_MODE_CHANGE_LEVEL
: PLAY_MODE_CHANGE_AREA);
s8 warpCourse = gLevelToCourseNumTable[sWarpDest.levelNum - 1];
if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL && warpCourse == COURSE_NONE) {
sReceivedLoadedActNum = 0;
}
/*return (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL)
? sWarpDest.levelNum
: 0;*/
}
int gPressedStart = 0;
@ -1044,29 +1053,27 @@ s32 play_mode_normal(void) {
// If either initiate_painting_warp or initiate_delayed_warp initiated a
// warp, change play mode accordingly.
if (sCurrPlayMode == PLAY_MODE_NORMAL) {
if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL) {
if (sWarpDest.type == WARP_TYPE_NOT_WARPING) {
set_play_mode(PLAY_MODE_CHANGE_LEVEL);
} else {
if (!gReceiveWarp) {
if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL) {
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL);
network_send_level_warp(FALSE);
network_send_level_warp_begin();
} else if (sTransitionTimer != 0) {
if (sWarpDest.type == WARP_TYPE_CHANGE_AREA) {
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_AREA);
network_send_level_warp_begin();
} else {
set_play_mode(PLAY_MODE_CHANGE_AREA);
}
} else if (pressed_pause()) {
lower_background_noise(1);
cancel_rumble();
gCameraMovementFlags |= CAM_MOVE_PAUSE_SCREEN;
set_play_mode(PLAY_MODE_PAUSED);
}
} else if (sTransitionTimer != 0) {
if (sWarpDest.type == WARP_TYPE_NOT_WARPING || gCurrentArea->index == sWarpDest.areaIdx) {
set_play_mode(PLAY_MODE_CHANGE_AREA);
} else {
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_AREA);
network_send_level_warp(FALSE);
}
} else if (pressed_pause()) {
lower_background_noise(1);
cancel_rumble();
gCameraMovementFlags |= CAM_MOVE_PAUSE_SCREEN;
set_play_mode(PLAY_MODE_PAUSED);
}
check_received_warp();
}
check_for_received_warp();
return 0;
}
@ -1088,7 +1095,7 @@ s32 play_mode_paused(void) {
gSavedCourseNum = COURSE_NONE;
}
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL);
network_send_level_warp(FALSE);
network_send_level_warp_begin();
} else if (gPauseScreenMode == 3) {
// We should only be getting "int 3" to here
initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0);
@ -1098,11 +1105,12 @@ s32 play_mode_paused(void) {
gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN;
check_received_warp();
return 0;
}
s32 play_mode_sync_level(void) {
check_for_received_warp();
check_received_warp();
return 0;
}
@ -1151,8 +1159,7 @@ s32 play_mode_change_area(void) {
sTransitionTimer -= 1;
}
if (sTransitionTimer < 0) { sTransitionTimer = 0; }
//! If sTransitionTimer is -1, this will miss.
if (sTransitionTimer == 0) {
sTransitionUpdate = NULL;
set_play_mode(PLAY_MODE_NORMAL);
@ -1210,7 +1217,8 @@ s32 update_level(void) {
changeLevel = play_mode_normal();
break;
case PLAY_MODE_PAUSED:
changeLevel = play_mode_normal() | play_mode_paused();
play_mode_normal();
changeLevel = play_mode_paused();
break;
case PLAY_MODE_CHANGE_AREA:
changeLevel = play_mode_change_area();

View file

@ -34,6 +34,7 @@ static struct Object *sStarSelectorModels[8];
// The act the course is loaded as, affects whether some objects spawn.
s8 sLoadedActNum;
s8 sReceivedLoadedActNum = 0;
// Number of obtained stars, excluding the coin star.
static u8 sObtainedStars;
@ -158,10 +159,6 @@ void bhv_act_selector_init(void) {
}
render_100_coin_star(stars);
if (gControlledWarp) {
network_send_inside_painting(TRUE, FALSE);
}
}
/**
@ -183,7 +180,7 @@ void bhv_act_selector_loop(void) {
if (gControlledWarp) {
s8 oldIndex = sSelectableStarIndex;
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sObtainedStars);
if (oldIndex != sSelectableStarIndex) { network_send_inside_painting(FALSE, FALSE); }
if (oldIndex != sSelectableStarIndex) { network_send_inside_painting(); }
}
starIndexCounter = sSelectableStarIndex;
for (i = 0; i < sVisibleStars; i++) {
@ -201,7 +198,7 @@ void bhv_act_selector_loop(void) {
if (gControlledWarp) {
s8 oldIndex = sSelectableStarIndex;
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sVisibleStars - 1);
if (oldIndex != sSelectableStarIndex) { network_send_inside_painting(FALSE, FALSE); }
if (oldIndex != sSelectableStarIndex) { network_send_inside_painting(); }
}
sSelectedActIndex = sSelectableStarIndex;
}
@ -452,6 +449,12 @@ s32 lvl_update_obj_and_load_act_button_actions(UNUSED s32 arg, UNUSED s32 unused
}
}
// apply the received act num
if (sReceivedLoadedActNum != 0) {
sLoadedActNum = sReceivedLoadedActNum;
sReceivedLoadedActNum = 0;
}
area_update_objects();
sActSelectorMenuTimer++;
return sLoadedActNum;
@ -470,5 +473,5 @@ void star_select_finish_selection(void) {
}
gDialogCourseActNum = sSelectedActIndex + 1;
if (gControlledWarp) { network_send_inside_painting(FALSE, TRUE); }
if (gControlledWarp) { network_send_inside_painting(); }
}

View file

@ -131,11 +131,11 @@ void network_send_spawn_star(struct Object* o, u8 starType, f32 x, f32 y, f32 z,
void network_receive_spawn_star(struct Packet* p);
// packet_level_warp.c
void network_send_level_warp(u8 done);
void network_send_level_warp_begin(void);
void network_receive_level_warp(struct Packet* p);
// packet_inside_painting.c
void network_send_inside_painting(u8 startOfEvent, u8 endOfEvent);
void network_send_inside_painting(void);
void network_receive_inside_painting(struct Packet* p);
// packet_collect_star.c

View file

@ -10,32 +10,27 @@ extern u8 gControlledWarp;
extern u8 sSelectableStarIndex;
extern u8 sSelectedActIndex;
extern s8 sLoadedActNum;
extern s8 sReceivedLoadedActNum;
#pragma pack(1)
struct PacketInsidePaintingData {
u8 seqId;
u8 eventId;
u8 starIndex;
u8 actIndex;
u8 loadedActNum;
};
static u8 eventId = 0;
static u8 remoteFinishedEventId = (u8)-1;
static u8 seqId = 0;
static u8 remoteLastSeqId = (u8)-1;
static void populate_packet_data(struct PacketInsidePaintingData* data) {
data->seqId = seqId;
data->eventId = eventId;
data->starIndex = sSelectableStarIndex;
data->actIndex = sSelectedActIndex;
data->loadedActNum = sLoadedActNum;
}
void network_send_inside_painting(u8 startOfEvent, u8 endOfEvent) {
if (startOfEvent) { eventId++; }
void network_send_inside_painting(void) {
struct PacketInsidePaintingData data = { 0 };
populate_packet_data(&data);
@ -59,10 +54,6 @@ void network_receive_inside_painting(struct Packet* p) {
return;
}
remoteLastSeqId = remote.seqId;
if (remote.eventId == remoteFinishedEventId || (remote.eventId == remoteFinishedEventId - 1)) {
LOG_INFO("we've finished this event, escape!");
return;
}
// two-player hack: gControlledWarp is a bool instead of an index
if (gControlledWarp) {
@ -71,14 +62,15 @@ void network_receive_inside_painting(struct Packet* p) {
}
LOG_INFO("received update");
eventId = remote.eventId;
sSelectableStarIndex = remote.starIndex;
sSelectedActIndex = remote.actIndex;
sLoadedActNum = remote.loadedActNum;
if (sReceivedLoadedActNum == 0) {
sReceivedLoadedActNum = remote.loadedActNum;
}
if (sLoadedActNum != 0) {
if (sReceivedLoadedActNum != 0) {
LOG_INFO("finished with painting");
remoteFinishedEventId = remote.eventId;
}
}

View file

@ -8,17 +8,22 @@
#include "pc/debuglog.h"
static u8 eventId = 0;
static u8 remoteFinishedEventId = (u8)-1;
static u8 remoteFinishedEventId[2] = { (u8)-1, (u8)-1 };
static u8 seqId = 0;
static u8 remoteLastSeqId = (u8)-1;
extern s16 D_80339EE0;
extern u8 gControlledWarp; // two-player hack
extern u8 gReceiveWarp;
extern struct WarpDest gReceiveWarpDest;
s16 saved_D_80339EE0 = 0;
struct WarpDest savedWarpNode = { 0 };
static clock_t lastDoneEvent = 0;
static bool isInWarp = FALSE;
#pragma pack(1)
struct PacketLevelWarpData {
u8 seqId;
@ -26,26 +31,64 @@ struct PacketLevelWarpData {
u8 done;
u8 controlledWarp;
struct WarpDest warpDest;
s16 D_80339EE0;
};
static void populate_packet_data(struct PacketLevelWarpData* data, bool done) {
static void populate_packet_data(struct PacketLevelWarpData* data, bool done, u8 packetEventId) {
data->seqId = seqId;
data->eventId = eventId;
data->eventId = packetEventId;
data->done = done;
data->controlledWarp = gControlledWarp;
data->warpDest = savedWarpNode;
data->D_80339EE0 = saved_D_80339EE0;
}
void network_send_level_warp(u8 done) {
if (!done) {
savedWarpNode = sWarpDest;
gControlledWarp = true;
eventId++;
LOG_INFO("new event [%d]!", eventId);
}
void network_send_level_warp_begin(void) {
assert(!isInWarp);
isInWarp = TRUE;
savedWarpNode = sWarpDest;
saved_D_80339EE0 = D_80339EE0;
float elapsedSinceDone = (clock() - lastDoneEvent) / CLOCKS_PER_SEC;
gControlledWarp = (elapsedSinceDone < 1.0f)
? (gNetworkType == NT_SERVER) // two-player hack
: true;
eventId++;
if (eventId == (u8)-1) { eventId++; }
LOG_INFO("new event [%d]!", eventId);
struct PacketLevelWarpData data = { 0 };
populate_packet_data(&data, done);
populate_packet_data(&data, false, eventId);
struct Packet p;
packet_init(&p, PACKET_LEVEL_WARP, true);
packet_write(&p, &data, sizeof(struct PacketLevelWarpData));
network_send(&p);
seqId++;
}
static void network_send_level_warp_repeat(void) {
assert(isInWarp);
struct PacketLevelWarpData data = { 0 };
populate_packet_data(&data, false, eventId);
struct Packet p;
packet_init(&p, PACKET_LEVEL_WARP, false);
packet_write(&p, &data, sizeof(struct PacketLevelWarpData));
network_send(&p);
seqId++;
}
static void network_send_level_warp_done(u8 remoteEventId) {
lastDoneEvent = clock();
isInWarp = FALSE;
struct PacketLevelWarpData data = { 0 };
populate_packet_data(&data, true, remoteEventId);
struct Packet p;
packet_init(&p, PACKET_LEVEL_WARP, true);
@ -57,6 +100,7 @@ void network_send_level_warp(u8 done) {
static void do_warp(void) {
gReceiveWarpDest = savedWarpNode;
D_80339EE0 = saved_D_80339EE0;
gReceiveWarp = TRUE;
}
@ -70,32 +114,46 @@ void network_receive_level_warp(struct Packet* p) {
return;
}
remoteLastSeqId = remote.seqId;
LOG_INFO("rx event [%d] last [%d]!", remote.eventId, remoteFinishedEventId);
if (remote.eventId == remoteFinishedEventId || (remote.eventId == remoteFinishedEventId - 1)) {
LOG_INFO("we've finished this event, escape!");
LOG_INFO("rx event [%d] last [%d, %d]", remote.eventId, remoteFinishedEventId[0], remoteFinishedEventId[1]);
if (remote.done && remote.eventId != eventId) {
LOG_INFO("remote has finished the wrong id!");
return;
}
if (!remote.done) {
if (remote.eventId == remoteFinishedEventId[0] || remote.eventId == remoteFinishedEventId[1]) {
LOG_INFO("we've finished this event, escape!");
return;
}
remoteFinishedEventId[1] = remoteFinishedEventId[0];
remoteFinishedEventId[0] = remote.eventId;
}
if (gNetworkType == NT_SERVER) {
if (sCurrPlayMode != PLAY_MODE_SYNC_LEVEL) {
if (!isInWarp && remote.done) {
LOG_INFO("client is done with warp, but so are we!");
return;
} else if (!isInWarp) {
// client initiated warp
LOG_INFO("client initiated warp!");
gControlledWarp = FALSE;
gControlledWarp = !remote.controlledWarp; // two-player hack
savedWarpNode = remote.warpDest;
eventId = remote.eventId;
remoteFinishedEventId = remote.eventId;
LOG_INFO("finished event [%d]!", remote.eventId);
saved_D_80339EE0 = remote.D_80339EE0;
do_warp();
network_send_level_warp(TRUE);
network_send_level_warp_done(remote.eventId);
return;
} else if (remote.done) {
} else if (remote.done && remote.eventId == eventId) {
// client done with warp
LOG_INFO("client is done with warp, lets-a-go!");
remoteFinishedEventId = remote.eventId;
do_warp();
isInWarp = FALSE;
return;
} else {
LOG_INFO("client initiated warp, but server is already warping!");
LOG_INFO("remote.done: %d, remote.eventId: %d!", remote.done, remote.eventId);
network_send_level_warp_repeat();
return;
}
}
@ -106,9 +164,8 @@ void network_receive_level_warp(struct Packet* p) {
LOG_INFO("server initiated warp!");
gControlledWarp = !remote.controlledWarp; // two-player hack
savedWarpNode = remote.warpDest;
eventId = remote.eventId;
remoteFinishedEventId = remote.eventId;
saved_D_80339EE0 = remote.D_80339EE0;
LOG_INFO("finished event [%d]!", remote.eventId);
do_warp();
network_send_level_warp(TRUE);
network_send_level_warp_done(remote.eventId);
}