From ed95bd317bc7376ab439822bd8ca11f0e5de191c Mon Sep 17 00:00:00 2001 From: MysterD Date: Sat, 14 Aug 2021 11:48:15 -0700 Subject: [PATCH] Resynchronized Koopa the Quick and race timers for late join --- src/game/behaviors/koopa.inc.c | 116 +++++++++++++++---------- src/game/level_update.c | 33 ++++++- src/game/level_update.h | 5 +- src/pc/network/network.h | 2 + src/pc/network/packets/packet_area.c | 22 +++++ src/pc/network/packets/packet_level.c | 2 - src/pc/network/packets/packet_object.c | 20 +++++ 7 files changed, 145 insertions(+), 55 deletions(-) diff --git a/src/game/behaviors/koopa.inc.c b/src/game/behaviors/koopa.inc.c index 8c4362673..488491304 100644 --- a/src/game/behaviors/koopa.inc.c +++ b/src/game/behaviors/koopa.inc.c @@ -65,8 +65,32 @@ static struct KoopaTheQuickProperties sKoopaTheQuickProperties[] = { { DIALOG_009, DIALOG_031, thi_seg7_trajectory_koopa, { 7100, -1300, -6000 } } }; -static u32 koopaForceStartRace = FALSE; -static u32 koopaForceEndRace = FALSE; +static u32 koopaPathedStartWaypoint = 0; +static u32 koopaPathedPrevWaypoint = 0; +static u32 koopaShotFromCannon = 0; +static u8 koopaWasInRace = false; + +static void bhv_koopa_the_quick_on_received_pre(u8 fromLocalIndex) { + koopaWasInRace = (o->oAction >= KOOPA_THE_QUICK_ACT_RACE); +} +static void bhv_koopa_the_quick_on_received_post(u8 fromLocalIndex) { + void* path = segmented_to_virtual(sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].path); + o->oPathedStartWaypoint = (struct Waypoint*)path + koopaPathedStartWaypoint; + o->oPathedPrevWaypoint = (struct Waypoint*)path + koopaPathedPrevWaypoint; + gMarioShotFromCannon = koopaShotFromCannon; +} + +static void bhv_koopa_the_quick_on_sent_pre(void) { + void* path = segmented_to_virtual(sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].path); + koopaPathedStartWaypoint = ((void*)o->oPathedStartWaypoint - path) / sizeof(struct Waypoint*); + koopaPathedPrevWaypoint = ((void*)o->oPathedPrevWaypoint - path) / sizeof(struct Waypoint*); + koopaShotFromCannon = gMarioShotFromCannon; +} + +void bhv_koopa_the_quick_override_ownership(u8* shouldOverride, u8* shouldOwn) { + *shouldOverride = TRUE; + *shouldOwn = (get_network_player_smallest_global() == gNetworkPlayerLocal); +} /** * Initialization function. @@ -84,18 +108,43 @@ void bhv_koopa_init(void) { o->oKoopaTheQuickRaceIndex = o->oKoopaMovementType - KOOPA_BP_KOOPA_THE_QUICK_BASE; o->oKoopaAgility = 4.0f; cur_obj_scale(3.0f); - - koopaForceStartRace = FALSE; - koopaForceEndRace = FALSE; } else { o->oKoopaAgility = 1.0f; } if (o->oKoopaMovementType >= KOOPA_BP_KOOPA_THE_QUICK_BASE) { // koopa the quick - network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); - network_init_object_field(o, &koopaForceStartRace); - + o->parentObj = cur_obj_nearest_object_with_behavior(bhvKoopaRaceEndpoint); + struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + so->on_received_pre = bhv_koopa_the_quick_on_received_pre; + so->on_received_post = bhv_koopa_the_quick_on_received_post; + so->on_sent_pre = bhv_koopa_the_quick_on_sent_pre; + so->override_ownership = bhv_koopa_the_quick_override_ownership; + network_init_object_field(o, &koopaPathedStartWaypoint); + network_init_object_field(o, &koopaPathedPrevWaypoint); + network_init_object_field(o, &koopaShotFromCannon); + network_init_object_field(o, &o->oPathedPrevWaypointFlags); + network_init_object_field(o, &o->oPathedTargetPitch); + network_init_object_field(o, &o->oPathedTargetYaw); + network_init_object_field(o, &o->oPosX); + network_init_object_field(o, &o->oPosY); + network_init_object_field(o, &o->oPosZ); + network_init_object_field(o, &o->oVelX); + network_init_object_field(o, &o->oVelY); + network_init_object_field(o, &o->oVelZ); + network_init_object_field(o, &o->oAction); + network_init_object_field(o, &o->oPrevAction); + network_init_object_field(o, &o->oSubAction); + network_init_object_field(o, &o->oTimer); + network_init_object_field(o, &o->oKoopaAgility); + network_init_object_field(o, &o->parentObj->oKoopaRaceEndpointRaceBegun); + network_init_object_field(o, &o->parentObj->oKoopaRaceEndpointRaceStatus); + network_init_object_field(o, &o->oForwardVel); + network_init_object_field(o, &o->oMoveAngleYaw); + network_init_object_field(o, &o->areaTimer); + o->areaTimerType = AREA_TIMER_TYPE_MAXIMUM; + o->areaTimer = 0; + o->areaTimerDuration = 60; } else { // normal koopa network_init_object(o, 4000.0f); @@ -567,19 +616,6 @@ static void koopa_the_quick_act_wait_before_race(void) { } } -static void koopa_the_quick_force_start_race(void) { - koopaForceStartRace = FALSE; - gMarioShotFromCannon = FALSE; - o->oAction = KOOPA_THE_QUICK_ACT_RACE; - o->oForwardVel = 0.0f; - - o->parentObj = cur_obj_nearest_object_with_behavior(bhvKoopaRaceEndpoint); - o->oPathedStartWaypoint = o->oPathedPrevWaypoint = segmented_to_virtual(sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].path); - - o->oKoopaTurningAwayFromWall = FALSE; - o->oFlags |= OBJ_FLAG_ACTIVE_FROM_AFAR; -} - u8 koopa_the_quick_act_show_init_text_continue_dialog(void) { return o->oAction == KOOPA_THE_QUICK_ACT_SHOW_INIT_TEXT; } /** @@ -605,10 +641,7 @@ static void koopa_the_quick_act_show_init_text(void) { o->oKoopaTurningAwayFromWall = FALSE; o->oFlags |= OBJ_FLAG_ACTIVE_FROM_AFAR; - koopaForceStartRace = TRUE; network_send_object(o); - koopaForceStartRace = FALSE; - ; } else if (response == 2) { o->oAction = KOOPA_THE_QUICK_ACT_WAIT_BEFORE_RACE; o->oKoopaTheQuickInitTextboxCooldown = 60; @@ -678,8 +711,10 @@ static void koopa_the_quick_act_race(void) { // Hitbox is slightly larger while racing cur_obj_push_mario_away_from_cylinder(180.0f, 300.0f); + struct Waypoint* lastPrevWaypoint = o->oPathedPrevWaypoint; if (cur_obj_follow_path(0) == PATH_REACHED_END) { o->oAction = KOOPA_THE_QUICK_ACT_DECELERATE; + if (network_owns_object(o)) { network_send_object(o); } } else { downhillSteepness = 1.0f + sins((s16)(f32) o->oPathedTargetPitch); cur_obj_rotate_yaw_toward(o->oPathedTargetYaw, (s32)(o->oKoopaAgility * 150.0f)); @@ -751,6 +786,10 @@ static void koopa_the_quick_act_race(void) { } } } + + if (lastPrevWaypoint != o->oPathedPrevWaypoint) { + if (network_owns_object(o)) { network_send_object(o); } + } } } @@ -764,6 +803,7 @@ static void koopa_the_quick_act_decelerate(void) { if (cur_obj_check_if_near_animation_end()) { o->oAction = KOOPA_THE_QUICK_ACT_STOP; o->oForwardVel = 3.0f; + if (network_owns_object(o)) { network_send_object(o); } } } @@ -777,6 +817,7 @@ static void koopa_the_quick_act_stop(void) { // KOOPA_SHELLED_ACT_STOPPED at the end if (o->oAction == KOOPA_SHELLED_ACT_STOPPED) { o->oAction = KOOPA_THE_QUICK_ACT_AFTER_RACE; + if (network_owns_object(o)) { network_send_object(o); } } } @@ -838,8 +879,6 @@ static void koopa_the_quick_update(void) { cur_obj_update_floor_and_walls(); obj_update_blinking(&o->oKoopaBlinkTimer, 10, 15, 3); - if (koopaForceStartRace) { koopa_the_quick_force_start_race(); } - switch (o->oAction) { case KOOPA_THE_QUICK_ACT_WAIT_BEFORE_RACE: case KOOPA_THE_QUICK_ACT_UNUSED1: @@ -868,7 +907,9 @@ static void koopa_the_quick_update(void) { } } - cur_obj_push_mario_away_from_cylinder(140.0f, 300.0f); + if (cur_obj_is_last_nat_update_per_frame()) { + cur_obj_push_mario_away_from_cylinder(140.0f, 300.0f); + } cur_obj_move_standard(-78); } @@ -909,28 +950,10 @@ void bhv_koopa_update(void) { obj_face_yaw_approach(o->oMoveAngleYaw, 0x600); } -void koopa_the_quick_force_end_race(void) { - o->oKoopaRaceEndpointRaceEnded = TRUE; - level_control_timer(TIMER_CONTROL_STOP); - - if (!o->oKoopaRaceEndpointKoopaFinished) { - play_race_fanfare(); - } - koopaForceEndRace = FALSE; -} - /** * Update function for bhvKoopaRaceEndpoint. */ void bhv_koopa_race_endpoint_update(void) { - if (!network_sync_object_initialized(o)) { - network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); - network_init_object_field(o, &o->oKoopaRaceEndpointRaceStatus); - network_init_object_field(o, &koopaForceEndRace); - } - - if (koopaForceEndRace) { koopa_the_quick_force_end_race(); } - if (o->oKoopaRaceEndpointRaceBegun && !o->oKoopaRaceEndpointRaceEnded) { struct Object* player = nearest_player_to_object(o); int distanceToPlayer = dist_between_objects(o, player); @@ -945,9 +968,6 @@ void bhv_koopa_race_endpoint_update(void) { } else { o->oKoopaRaceEndpointRaceStatus = 1; } - koopaForceEndRace = TRUE; - network_send_object(o); - koopaForceEndRace = FALSE; } } } diff --git a/src/game/level_update.c b/src/game/level_update.c index 51f6ca3c3..8d86193cc 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -180,26 +180,43 @@ s8 gInWarpCheckpoint = 0; u8 unused3[4]; u8 unused4[2]; +u32 gControlTimerStartNat = 0; +u32 gControlTimerStopNat = 0; + +u8 level_control_timer_running(void) { + return sTimerRunning; +} + u16 level_control_timer(s32 timerOp) { switch (timerOp) { case TIMER_CONTROL_SHOW: gHudDisplay.flags |= HUD_DISPLAY_FLAG_TIMER; sTimerRunning = FALSE; gHudDisplay.timer = 0; + gControlTimerStartNat = 0; + gControlTimerStopNat = 0; break; case TIMER_CONTROL_START: - sTimerRunning = TRUE; + if (!sTimerRunning) { + sTimerRunning = TRUE; + gControlTimerStartNat = gNetworkAreaTimer; + } break; case TIMER_CONTROL_STOP: - sTimerRunning = FALSE; + if (sTimerRunning) { + sTimerRunning = FALSE; + gControlTimerStopNat = gNetworkAreaTimer; + } break; case TIMER_CONTROL_HIDE: gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_TIMER; sTimerRunning = FALSE; gHudDisplay.timer = 0; + gControlTimerStartNat = 0; + gControlTimerStopNat = 0; break; } @@ -1034,8 +1051,16 @@ s32 play_mode_normal(void) { warp_area(); check_instant_warp(); - if (sTimerRunning && gHudDisplay.timer < 17999) { - gHudDisplay.timer += 1; + if (sTimerRunning) { + gHudDisplay.timer = gNetworkAreaTimer - gControlTimerStartNat; + if (gHudDisplay.timer >= 17999) { + gHudDisplay.timer = 17999; + } + } else if (gControlTimerStopNat > 0) { + gHudDisplay.timer = gControlTimerStopNat - gControlTimerStartNat; + if (gHudDisplay.timer >= 17999) { + gHudDisplay.timer = 17999; + } } area_update_objects(); diff --git a/src/game/level_update.h b/src/game/level_update.h index 977456bb5..bdff2e126 100644 --- a/src/game/level_update.h +++ b/src/game/level_update.h @@ -122,6 +122,9 @@ struct HudDisplay { extern struct HudDisplay gHudDisplay; extern s8 gShouldNotPlayCastleMusic; +extern u32 gControlTimerStartNat; +extern u32 gControlTimerStopNat; + enum HUDDisplayFlag { HUD_DISPLAY_FLAG_LIVES = 0x0001, HUD_DISPLAY_FLAG_COIN_COUNT = 0x0002, @@ -136,7 +139,7 @@ enum HUDDisplayFlag { HUD_DISPLAY_DEFAULT = HUD_DISPLAY_FLAG_LIVES | HUD_DISPLAY_FLAG_COIN_COUNT | HUD_DISPLAY_FLAG_STAR_COUNT | HUD_DISPLAY_FLAG_CAMERA_AND_POWER | HUD_DISPLAY_FLAG_KEYS | HUD_DISPLAY_FLAG_UNKNOWN_0020 }; - +u8 level_control_timer_running(void); u16 level_control_timer(s32 timerOp); void fade_into_special_warp(u32 arg, u32 color); void load_level_init_text(u32 arg); diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 4f9bdd30c..7999db386 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -60,6 +60,8 @@ struct SyncObject { u8 (*ignore_if_true)(void); void (*on_received_pre)(u8 fromLocalIndex); void (*on_received_post)(u8 fromLocalIndex); + void (*on_sent_pre)(void); + void (*on_sent_post)(void); void (*override_ownership)(u8* shouldOverride, u8* shouldOwn); void* extraFields[MAX_SYNC_OBJECT_FIELDS]; }; diff --git a/src/pc/network/packets/packet_area.c b/src/pc/network/packets/packet_area.c index e4a335cb3..8668e2444 100644 --- a/src/pc/network/packets/packet_area.c +++ b/src/pc/network/packets/packet_area.c @@ -33,6 +33,8 @@ void area_remove_sync_ids_clear(void) { void network_send_area(struct NetworkPlayer* toNp) { extern s16 gCurrCourseNum, gCurrActStarNum, gCurrLevelNum, gCurrAreaIndex; + bool levelControlTimerRunning = level_control_timer_running(); + bool levelControlTimerVisible = (gHudDisplay.flags & HUD_DISPLAY_FLAG_TIMER) ? 1 : 0; packet_ordered_begin(); { @@ -49,6 +51,12 @@ void network_send_area(struct NetworkPlayer* toNp) { packet_write(&p, &gNetworkAreaTimer, sizeof(u32)); packet_write(&p, gEnvironmentLevels, sizeof(s32)); + // level control timer + packet_write(&p, &levelControlTimerVisible, sizeof(u8)); + packet_write(&p, &levelControlTimerRunning, sizeof(u8)); + packet_write(&p, &gControlTimerStartNat, sizeof(u32)); + packet_write(&p, &gControlTimerStopNat, sizeof(u32)); + // write sync id removals packet_write(&p, &sRemoveSyncIdsIndex, sizeof(u8)); for (int i = 0; i < sRemoveSyncIdsIndex; i++) { @@ -146,6 +154,20 @@ void network_receive_area(struct Packet* p) { gNetworkAreaTimerClock = clock_elapsed_ticks() - gNetworkAreaTimer; packet_read(p, gEnvironmentLevels, sizeof(s32)); + // read control timer variables + bool levelControlTimerRunning = false; + bool levelControlTimerVisible = false; + packet_read(p, &levelControlTimerVisible, sizeof(u8)); + packet_read(p, &levelControlTimerRunning, sizeof(u8)); + if (levelControlTimerVisible) { + level_control_timer(TIMER_CONTROL_SHOW); + } + if (levelControlTimerRunning) { + level_control_timer(TIMER_CONTROL_START); + } + packet_read(p, &gControlTimerStartNat, sizeof(u32)); + packet_read(p, &gControlTimerStopNat, sizeof(u32)); + // read removed sync ids area_remove_sync_ids_clear(); packet_read(p, &sRemoveSyncIdsIndex, sizeof(u8)); diff --git a/src/pc/network/packets/packet_level.c b/src/pc/network/packets/packet_level.c index e2d7184a1..129f90fb5 100644 --- a/src/pc/network/packets/packet_level.c +++ b/src/pc/network/packets/packet_level.c @@ -27,7 +27,6 @@ void network_send_level(struct NetworkPlayer* toNp, bool sendArea) { packet_write(&p, &gMarioStates[0].numCoins, sizeof(s16)); packet_write(&p, &gRedCoinsCollected, sizeof(u8)); packet_write(&p, &gPssSlideStarted, sizeof(u8)); - packet_write(&p, &gHudDisplay.timer, sizeof(u16)); packet_write(&p, &gTTCSpeedSetting, sizeof(s16)); // send level packet @@ -72,7 +71,6 @@ void network_receive_level(struct Packet* p) { packet_read(p, &gMarioStates[0].numCoins, sizeof(s16)); packet_read(p, &redCoinsCollected, sizeof(u8)); packet_read(p, &gPssSlideStarted, sizeof(u8)); - packet_read(p, &gHudDisplay.timer, sizeof(u16)); packet_read(p, &gTTCSpeedSetting, sizeof(s16)); // likely doesn't work after level load.. but it could // hacky way to override red coins collected diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 107f673f0..0b69080b1 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -99,6 +99,8 @@ struct SyncObject* network_init_object(struct Object *o, float maxSyncDistance) so->ignore_if_true = NULL; so->on_received_pre = NULL; so->on_received_post = NULL; + so->on_sent_pre = NULL; + so->on_sent_post = NULL; so->override_ownership = NULL; so->syncDeathEvent = true; so->randomSeed = (u16)(o->oSyncID * 7951); @@ -429,6 +431,15 @@ void network_send_object_reliability(struct Object* o, bool reliable) { return; } + // trigger on_sent_pre callback + if (so->on_sent_pre != NULL) { + extern struct Object* gCurrentObject; + struct Object* tmp = gCurrentObject; + gCurrentObject = so->o; + so->on_sent_pre(); + gCurrentObject = tmp; + } + // always send a new event ID so->txEventId++; so->clockSinceUpdate = clock_elapsed(); @@ -457,6 +468,15 @@ void network_send_object_reliability(struct Object* o, bool reliable) { // send the packet out network_send(&p); + + // trigger on_sent_post callback + if (so->on_sent_post != NULL) { + extern struct Object* gCurrentObject; + struct Object* tmp = gCurrentObject; + gCurrentObject = so->o; + so->on_sent_post(); + gCurrentObject = tmp; + } } void network_receive_object(struct Packet* p) {