diff --git a/src/game/level_update.c b/src/game/level_update.c index 66d9b3a1b..3dbc5568b 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -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(); diff --git a/src/menu/star_select.c b/src/menu/star_select.c index 6aa8ae62c..0774f36e7 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -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(); } } diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 3e32e3866..634c4dc29 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -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 diff --git a/src/pc/network/packets/packet_inside_painting.c b/src/pc/network/packets/packet_inside_painting.c index 2862873f9..2e44b3e6e 100644 --- a/src/pc/network/packets/packet_inside_painting.c +++ b/src/pc/network/packets/packet_inside_painting.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; } } diff --git a/src/pc/network/packets/packet_level_warp.c b/src/pc/network/packets/packet_level_warp.c index 0560cabe2..45d7df58b 100644 --- a/src/pc/network/packets/packet_level_warp.c +++ b/src/pc/network/packets/packet_level_warp.c @@ -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); }