mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-22 03:55:11 +00:00
More level transition synchronization rewrites
I believe this fixes #51
This commit is contained in:
parent
791423ff98
commit
163527401e
5 changed files with 135 additions and 75 deletions
|
@ -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,19 +1053,16 @@ 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 (!gReceiveWarp) {
|
||||
if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL) {
|
||||
if (sWarpDest.type == WARP_TYPE_NOT_WARPING) {
|
||||
set_play_mode(PLAY_MODE_CHANGE_LEVEL);
|
||||
} else {
|
||||
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_NOT_WARPING || gCurrentArea->index == sWarpDest.areaIdx) {
|
||||
set_play_mode(PLAY_MODE_CHANGE_AREA);
|
||||
} else {
|
||||
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(FALSE);
|
||||
network_send_level_warp_begin();
|
||||
} else {
|
||||
set_play_mode(PLAY_MODE_CHANGE_AREA);
|
||||
}
|
||||
} else if (pressed_pause()) {
|
||||
lower_background_noise(1);
|
||||
|
@ -1065,8 +1071,9 @@ s32 play_mode_normal(void) {
|
|||
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();
|
||||
|
|
|
@ -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(); }
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
void network_send_level_warp_begin(void) {
|
||||
assert(!isInWarp);
|
||||
isInWarp = TRUE;
|
||||
savedWarpNode = sWarpDest;
|
||||
gControlledWarp = true;
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue