From 8c650a5b7de6d82a25702ee5a0aea7cacb682ef3 Mon Sep 17 00:00:00 2001 From: MysterD Date: Mon, 24 Aug 2020 18:33:53 -0700 Subject: [PATCH] Created system to reserve sections of SyncIDs per client This allows clients to spawn a new sync object after the level loads and synchronize it. Changed how un-initialized sync objects are detected Koopa shells are the first thing to use this new system Removed network_object_settings() command, instead explicitly setting the sync object parameters --- levels/castle_grounds/script.c | 5 +- src/game/behaviors/blue_coin.inc.c | 2 +- src/game/behaviors/bomp.inc.c | 4 +- src/game/behaviors/bowling_ball.inc.c | 17 ++--- src/game/behaviors/breakable_wall.inc.c | 2 +- src/game/behaviors/bullet_bill.inc.c | 2 +- src/game/behaviors/cannon.inc.c | 6 +- src/game/behaviors/capswitch.inc.c | 2 +- src/game/behaviors/chain_chomp.inc.c | 4 +- .../behaviors/checkerboard_platform.inc.c | 6 +- src/game/behaviors/clam.inc.c | 2 +- src/game/behaviors/exclamation_box.inc.c | 2 +- src/game/behaviors/jrb_ship.inc.c | 14 ++-- src/game/behaviors/kickable_board.inc.c | 2 +- src/game/behaviors/king_bobomb.inc.c | 2 +- src/game/behaviors/koopa.inc.c | 13 +++- src/game/behaviors/koopa_shell.inc.c | 2 +- .../behaviors/koopa_shell_underwater.inc.c | 2 +- src/game/behaviors/mushroom_1up.inc.c | 10 +-- src/game/behaviors/piranha_plant.inc.c | 2 +- src/game/behaviors/platform_on_track.inc.c | 8 ++- src/game/behaviors/purple_switch.inc.c | 2 +- src/game/behaviors/rotating_platform.inc.c | 2 +- src/game/behaviors/sliding_platform.inc.c | 2 +- src/game/behaviors/spindrift.inc.c | 2 +- src/game/behaviors/thwomp.inc.c | 2 +- src/game/behaviors/tower_platform.inc.c | 4 +- src/game/behaviors/tuxie.inc.c | 4 +- src/game/behaviors/ukiki.inc.c | 2 +- src/game/behaviors/water_bomb.inc.c | 8 ++- src/game/behaviors/whomp.inc.c | 2 +- src/game/level_update.c | 2 + src/game/object_helpers.c | 4 +- src/game/object_helpers.h | 2 +- src/pc/network/network.c | 23 ++++++ src/pc/network/network.h | 17 ++++- src/pc/network/packets/packet_object.c | 48 ++++++++----- src/pc/network/packets/packet_reservation.c | 72 +++++++++++++++++++ src/pc/network/packets/packet_spawn_objects.c | 17 ++++- 39 files changed, 240 insertions(+), 84 deletions(-) create mode 100644 src/pc/network/packets/packet_reservation.c diff --git a/levels/castle_grounds/script.c b/levels/castle_grounds/script.c index e198eac4..abb6186e 100644 --- a/levels/castle_grounds/script.c +++ b/levels/castle_grounds/script.c @@ -90,9 +90,9 @@ static const LevelScript script_func_local_4[] = { OBJECT(/*model*/ MODEL_BUTTERFLY, /*pos*/ -1204, 326, 3296, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvButterfly), OBJECT(/*model*/ MODEL_YOSHI, /*pos*/ 0, 3174, -5625, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvYoshi), // TESTING BELOW - OBJECT(/*model*/ MODEL_BLACK_BOBOMB, /*pos*/ -528, 260, 4664, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvBobomb), + OBJECT(/*model*/ MODEL_KOOPA_WITH_SHELL, /*pos*/ -528, 260, 3264, /*angle*/ 0, 0, 0, /*behParam*/ 0x00010000, /*beh*/ bhvKoopa), //OBJECT(/*model*/ MODEL_BLACK_BOBOMB, /*pos*/ -1028, 260, 3664, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvBobomb), - OBJECT(/*model*/ MODEL_NONE, /*pos*/ -528, 260, 3264, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvGoombaTripletSpawner), + //OBJECT(/*model*/ MODEL_NONE, /*pos*/ -528, 260, 3264, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvGoombaTripletSpawner), RETURN(), }; @@ -113,6 +113,7 @@ const LevelScript level_castle_grounds_entry[] = { JUMP_LINK(script_func_global_1), JUMP_LINK(script_func_global_11), JUMP_LINK(script_func_global_16), + JUMP_LINK(script_func_global_15), // <--- TESTING LOAD_MODEL_FROM_GEO(MODEL_LEVEL_GEOMETRY_03, castle_grounds_geo_0006F4), LOAD_MODEL_FROM_GEO(MODEL_CASTLE_GROUNDS_BUBBLY_TREE, bubbly_tree_geo), LOAD_MODEL_FROM_GEO(MODEL_CASTLE_GROUNDS_WARP_PIPE, warp_pipe_geo), diff --git a/src/game/behaviors/blue_coin.inc.c b/src/game/behaviors/blue_coin.inc.c index 067dfbbf..d35d63ad 100644 --- a/src/game/behaviors/blue_coin.inc.c +++ b/src/game/behaviors/blue_coin.inc.c @@ -60,7 +60,7 @@ void bhv_hidden_blue_coin_loop(void) { * Update function for bhvBlueCoinSwitch. */ void bhv_blue_coin_switch_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oVelY); diff --git a/src/game/behaviors/bomp.inc.c b/src/game/behaviors/bomp.inc.c index 29ca5fd1..dfb5abbb 100644 --- a/src/game/behaviors/bomp.inc.c +++ b/src/game/behaviors/bomp.inc.c @@ -4,7 +4,7 @@ void bhv_small_bomp_init(void) { o->oFaceAngleYaw -= 0x4000; o->oSmallBompInitX = o->oPosX; o->oTimer = random_float() * 100.0f; - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oForwardVel); @@ -70,7 +70,7 @@ void bhv_small_bomp_loop(void) { void bhv_large_bomp_init(void) { o->oMoveAngleYaw += 0x4000; o->oTimer = random_float() * 100.0f; - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oForwardVel); diff --git a/src/game/behaviors/bowling_ball.inc.c b/src/game/behaviors/bowling_ball.inc.c index 4e7e28ee..249a4bfe 100644 --- a/src/game/behaviors/bowling_ball.inc.c +++ b/src/game/behaviors/bowling_ball.inc.c @@ -180,9 +180,9 @@ void bhv_generic_bowling_ball_spawner_init(void) { } void bhv_generic_bowling_ball_spawner_loop(void) { - if (o->oSyncID == 0) { - network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); - network_object_settings(o, FALSE, 0, TRUE, NULL); + if (!network_sync_object_initialized(o)) { + struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + so->keepRandomSeed = TRUE; } struct Object *bowlingBall; @@ -217,9 +217,9 @@ void bhv_generic_bowling_ball_spawner_loop(void) { } void bhv_thi_bowling_ball_spawner_loop(void) { - if (o->oSyncID == 0) { - network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); - network_object_settings(o, FALSE, 0, TRUE, NULL); + if (!network_sync_object_initialized(o)) { + struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + so->keepRandomSeed = TRUE; } struct Object *bowlingBall; @@ -253,8 +253,9 @@ void bhv_bob_pit_bowling_ball_init(void) { o->oFriction = 1.0f; o->oBuoyancy = 2.0f; - network_init_object(o, 5000.0f); - network_object_settings(o, FALSE, 5.0f, TRUE, NULL); + struct SyncObject* so = network_init_object(o, 5000.0f); + so->maxUpdateRate = 5.0f; + so->keepRandomSeed = TRUE; } void bhv_bob_pit_bowling_ball_loop(void) { diff --git a/src/game/behaviors/breakable_wall.inc.c b/src/game/behaviors/breakable_wall.inc.c index 2da01a10..fcf88117 100644 --- a/src/game/behaviors/breakable_wall.inc.c +++ b/src/game/behaviors/breakable_wall.inc.c @@ -1,7 +1,7 @@ // breakable_wall.c.inc void bhv_wf_breakable_wall_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oBreakableWallForce); } diff --git a/src/game/behaviors/bullet_bill.inc.c b/src/game/behaviors/bullet_bill.inc.c index 5af83b0d..ab97d2e2 100644 --- a/src/game/behaviors/bullet_bill.inc.c +++ b/src/game/behaviors/bullet_bill.inc.c @@ -7,7 +7,7 @@ void bhv_white_puff_smoke_init(void) { void bhv_bullet_bill_init(void) { o->oBulletBillInitialMoveYaw = o->oMoveAngleYaw; - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, 4000.0f); network_init_object_field(o, &o->oFaceAnglePitch); network_init_object_field(o, &o->oFaceAngleRoll); diff --git a/src/game/behaviors/cannon.inc.c b/src/game/behaviors/cannon.inc.c index be5583d5..6eca01cb 100644 --- a/src/game/behaviors/cannon.inc.c +++ b/src/game/behaviors/cannon.inc.c @@ -147,9 +147,9 @@ u8 unused0EA1FC[] = { 2, 0, 0, 0, 0, 0, 0, 0, 63, 128, 0, 0, 2, 0, 0, 0 u8 cannon_ignore_remote_updates(struct Object* object) { return object->oCannonIsLocal; } void bhv_cannon_base_loop(void) { - if (o->oSyncID == 0) { - network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); - network_object_settings(o, FALSE, 0, FALSE, &cannon_ignore_remote_updates); + if (!network_sync_object_initialized(o)) { + struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + so->ignore_if_true = &cannon_ignore_remote_updates; network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oTimer); network_init_object_field(o, &o->oCannonUnk10C); diff --git a/src/game/behaviors/capswitch.inc.c b/src/game/behaviors/capswitch.inc.c index 4ed61821..d2d8bc1d 100644 --- a/src/game/behaviors/capswitch.inc.c +++ b/src/game/behaviors/capswitch.inc.c @@ -60,7 +60,7 @@ void (*sCapSwitchActions[])(void) = { cap_switch_act_0, cap_switch_act_1, cap_switch_act_2, cap_switch_act_3 }; void bhv_cap_switch_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &capSwitchForcePress); } diff --git a/src/game/behaviors/chain_chomp.inc.c b/src/game/behaviors/chain_chomp.inc.c index 3b31ace2..cd5cb376 100644 --- a/src/game/behaviors/chain_chomp.inc.c +++ b/src/game/behaviors/chain_chomp.inc.c @@ -491,7 +491,7 @@ static void chain_chomp_act_unload_chain(void) { * Update function for chain chomp. */ void bhv_chain_chomp_update(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, 1000.0f); network_init_object_field(o, &o->oChainChompUnk104); network_init_object_field(o, &o->header.gfx.unk38.animFrame); @@ -514,7 +514,7 @@ void bhv_chain_chomp_update(void) { * Update function for wooden post. */ void bhv_wooden_post_update(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oWoodenPostMarioPounding); network_init_object_field(o, &o->oWoodenPostOffsetY); diff --git a/src/game/behaviors/checkerboard_platform.inc.c b/src/game/behaviors/checkerboard_platform.inc.c index 740a8f02..9a370585 100644 --- a/src/game/behaviors/checkerboard_platform.inc.c +++ b/src/game/behaviors/checkerboard_platform.inc.c @@ -45,8 +45,10 @@ void checkerboard_plat_act_rotate(s32 a0, s16 a1) { void bhv_checkerboard_platform_init(void) { o->oCheckerBoardPlatformUnkFC = o->parentObj->oBehParams2ndByte; - network_init_object(o, 1000.0f); - network_object_settings(o, TRUE, 5.0f, TRUE, NULL); + struct SyncObject* so = network_init_object(o, 1000.0f); + so->fullObjectSync = TRUE; + so->maxUpdateRate = 5.0f; + so->keepRandomSeed = TRUE; } void bhv_checkerboard_platform_loop(void) { diff --git a/src/game/behaviors/clam.inc.c b/src/game/behaviors/clam.inc.c index 7d05cd7c..ac3693e8 100644 --- a/src/game/behaviors/clam.inc.c +++ b/src/game/behaviors/clam.inc.c @@ -56,7 +56,7 @@ void clam_act_1(void) { } void bhv_clam_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oTimer); diff --git a/src/game/behaviors/exclamation_box.inc.c b/src/game/behaviors/exclamation_box.inc.c index e4e056a4..305d3267 100644 --- a/src/game/behaviors/exclamation_box.inc.c +++ b/src/game/behaviors/exclamation_box.inc.c @@ -156,7 +156,7 @@ void (*sExclamationBoxActions[])(void) = { exclamation_box_act_0, exclamation_bo exclamation_box_act_4, exclamation_box_act_5 }; void bhv_exclamation_box_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oExclamationBoxForce); } diff --git a/src/game/behaviors/jrb_ship.inc.c b/src/game/behaviors/jrb_ship.inc.c index a5f23c7a..14491560 100644 --- a/src/game/behaviors/jrb_ship.inc.c +++ b/src/game/behaviors/jrb_ship.inc.c @@ -21,9 +21,10 @@ void bhv_sunken_ship_part_loop(void) { } void bhv_ship_part_3_loop(void) { - if (o->oSyncID == 0) { - network_init_object(o, 4000.0f); - network_object_settings(o, FALSE, 5.0f, TRUE, NULL); + if (!network_sync_object_initialized(o)) { + struct SyncObject* so = network_init_object(o, 4000.0f); + so->maxUpdateRate = 5.0f; + so->keepRandomSeed = TRUE; network_init_object_field(o, &o->oFaceAnglePitch); network_init_object_field(o, &o->oFaceAngleRoll); network_init_object_field(o, &o->oShipPart3UnkF4); @@ -42,9 +43,10 @@ void bhv_ship_part_3_loop(void) { } void bhv_jrb_sliding_box_loop(void) { - if (o->oSyncID == 0) { - network_init_object(o, 4000.0f); - network_object_settings(o, FALSE, 5.0f, TRUE, NULL); + if (!network_sync_object_initialized(o)) { + struct SyncObject* so = network_init_object(o, 4000.0f); + so->maxUpdateRate = 5.0f; + so->keepRandomSeed = TRUE; network_init_object_field(o, &o->oFaceAnglePitch); network_init_object_field(o, &o->oFaceAngleRoll); network_init_object_field(o, &o->oJrbSlidingBoxUnkF8); diff --git a/src/game/behaviors/kickable_board.inc.c b/src/game/behaviors/kickable_board.inc.c index cf6c1851..5413b4d4 100644 --- a/src/game/behaviors/kickable_board.inc.c +++ b/src/game/behaviors/kickable_board.inc.c @@ -27,7 +27,7 @@ void init_kickable_board_rock(void) { void bhv_kickable_board_loop(void) { struct MarioState* marioState = nearest_mario_state_to_object(o); - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oAngleVelPitch); diff --git a/src/game/behaviors/king_bobomb.inc.c b/src/game/behaviors/king_bobomb.inc.c index 67422a37..290604a9 100644 --- a/src/game/behaviors/king_bobomb.inc.c +++ b/src/game/behaviors/king_bobomb.inc.c @@ -352,7 +352,7 @@ void king_bobomb_move(void) { } void bhv_king_bobomb_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, 4000.0f); network_init_object_field(o, &o->oKingBobombUnk88); network_init_object_field(o, &o->oFlags); diff --git a/src/game/behaviors/koopa.inc.c b/src/game/behaviors/koopa.inc.c index 4287abd9..ba11280e 100644 --- a/src/game/behaviors/koopa.inc.c +++ b/src/game/behaviors/koopa.inc.c @@ -300,7 +300,16 @@ void shelled_koopa_attack_handler(s32 attackType) { } cur_obj_set_model(MODEL_KOOPA_WITHOUT_SHELL); - spawn_object(o, MODEL_KOOPA_SHELL, bhvKoopaShell); + + struct MarioState* marioState = nearest_mario_state_to_object(o); + if (marioState->playerIndex == 0) { + struct Object* shell = spawn_object(o, MODEL_KOOPA_SHELL, bhvKoopaShell); + network_set_sync_id(shell); + + struct Object* spawn_objects[] = { shell }; + u32 models[] = { MODEL_KOOPA_SHELL }; + network_send_spawn_objects(spawn_objects, models, 1); + } //! Because bob-ombs/corkboxes come after koopa in processing order, // they can interact with the koopa on the same frame that this @@ -917,7 +926,7 @@ void koopa_the_quick_force_end_race(void) { * Update function for bhvKoopaRaceEndpoint. */ void bhv_koopa_race_endpoint_update(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &koopaForceEndRace); } diff --git a/src/game/behaviors/koopa_shell.inc.c b/src/game/behaviors/koopa_shell.inc.c index 73bd19ab..2ca3c3fe 100644 --- a/src/game/behaviors/koopa_shell.inc.c +++ b/src/game/behaviors/koopa_shell.inc.c @@ -52,7 +52,7 @@ void koopa_shell_spawn_sparkles(f32 a) { } void bhv_koopa_shell_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, 500.0f); } diff --git a/src/game/behaviors/koopa_shell_underwater.inc.c b/src/game/behaviors/koopa_shell_underwater.inc.c index 45f411f7..5ffbd273 100644 --- a/src/game/behaviors/koopa_shell_underwater.inc.c +++ b/src/game/behaviors/koopa_shell_underwater.inc.c @@ -17,7 +17,7 @@ void set_koopa_shell_underwater_hitbox(void) { } void bhv_koopa_shell_underwater_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, 500.0f); } switch (o->oHeldState) { diff --git a/src/game/behaviors/mushroom_1up.inc.c b/src/game/behaviors/mushroom_1up.inc.c index 359d8a21..eea21e38 100644 --- a/src/game/behaviors/mushroom_1up.inc.c +++ b/src/game/behaviors/mushroom_1up.inc.c @@ -212,7 +212,7 @@ void bhv_1up_jump_on_approach_loop(void) { } void bhv_1up_hidden_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oVelY); network_init_object_field(o, &o->oAction); @@ -260,7 +260,7 @@ void bhv_1up_hidden_loop(void) { } void bhv_1up_hidden_trigger_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->o1UpForceSpawn); } @@ -277,7 +277,7 @@ void bhv_1up_hidden_trigger_loop(void) { } void bhv_1up_hidden_in_pole_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oVelY); network_init_object_field(o, &o->oAction); @@ -318,7 +318,7 @@ void bhv_1up_hidden_in_pole_loop(void) { } void bhv_1up_hidden_in_pole_trigger_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->o1UpForceSpawn); } @@ -337,7 +337,7 @@ void bhv_1up_hidden_in_pole_trigger_loop(void) { } void bhv_1up_hidden_in_pole_spawner_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->o1UpForceSpawn); } diff --git a/src/game/behaviors/piranha_plant.inc.c b/src/game/behaviors/piranha_plant.inc.c index b6c724b4..2054baf7 100644 --- a/src/game/behaviors/piranha_plant.inc.c +++ b/src/game/behaviors/piranha_plant.inc.c @@ -360,7 +360,7 @@ void (*TablePiranhaPlantActions[])(void) = { * Main loop for bhvPiranhaPlant. */ void bhv_piranha_plant_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oInteractStatus); diff --git a/src/game/behaviors/platform_on_track.inc.c b/src/game/behaviors/platform_on_track.inc.c index fd6e0b19..9d64cfe2 100644 --- a/src/game/behaviors/platform_on_track.inc.c +++ b/src/game/behaviors/platform_on_track.inc.c @@ -53,9 +53,11 @@ static void platform_on_track_mario_not_on_platform(void) { */ void bhv_platform_on_track_init(void) { - if (o->oSyncID == 0) { - network_init_object(o, 1000.0f); - network_object_settings(o, TRUE, 5.0f, TRUE, NULL); + if (!network_sync_object_initialized(o)) { + struct SyncObject* so = network_init_object(o, 1000.0f); + so->fullObjectSync = TRUE; + so->maxUpdateRate = 5.0f; + so->keepRandomSeed = TRUE; } if (!(o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM)) { diff --git a/src/game/behaviors/purple_switch.inc.c b/src/game/behaviors/purple_switch.inc.c index dcc4b6be..b9716619 100644 --- a/src/game/behaviors/purple_switch.inc.c +++ b/src/game/behaviors/purple_switch.inc.c @@ -7,7 +7,7 @@ */ void bhv_purple_switch_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oTimer); diff --git a/src/game/behaviors/rotating_platform.inc.c b/src/game/behaviors/rotating_platform.inc.c index 89e595b4..4190d913 100644 --- a/src/game/behaviors/rotating_platform.inc.c +++ b/src/game/behaviors/rotating_platform.inc.c @@ -9,7 +9,7 @@ struct WFRotatingPlatformData sWFRotatingPlatformData[] = { }; void bhv_wf_rotating_wooden_platform_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oAngleVelYaw); diff --git a/src/game/behaviors/sliding_platform.inc.c b/src/game/behaviors/sliding_platform.inc.c index aa2cbf9e..74fcac9e 100644 --- a/src/game/behaviors/sliding_platform.inc.c +++ b/src/game/behaviors/sliding_platform.inc.c @@ -21,7 +21,7 @@ void bhv_wf_sliding_platform_init(void) { o->oTimer = random_float() * 100.0f; - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oMoveAngleYaw); diff --git a/src/game/behaviors/spindrift.inc.c b/src/game/behaviors/spindrift.inc.c index 73cda1a1..348c12c2 100644 --- a/src/game/behaviors/spindrift.inc.c +++ b/src/game/behaviors/spindrift.inc.c @@ -13,7 +13,7 @@ struct ObjectHitbox sSpindriftHitbox = { }; void bhv_spindrift_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, 4000.0f); network_init_object_field(o, &o->oFlags); } diff --git a/src/game/behaviors/thwomp.inc.c b/src/game/behaviors/thwomp.inc.c index 46e70449..618a8a9e 100644 --- a/src/game/behaviors/thwomp.inc.c +++ b/src/game/behaviors/thwomp.inc.c @@ -55,7 +55,7 @@ void (*sGrindelThwompActions[])(void) = { grindel_thwomp_act_0, grindel_thwomp_a grindel_thwomp_act_4 }; void bhv_grindel_thwomp_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oPosY); diff --git a/src/game/behaviors/tower_platform.inc.c b/src/game/behaviors/tower_platform.inc.c index dbba9d27..395a38a0 100644 --- a/src/game/behaviors/tower_platform.inc.c +++ b/src/game/behaviors/tower_platform.inc.c @@ -11,7 +11,7 @@ void bhv_wf_solid_tower_platform_loop(void) { } void bhv_wf_elevator_tower_platform_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oPosY); @@ -55,7 +55,7 @@ void bhv_wf_elevator_tower_platform_loop(void) { } void bhv_wf_sliding_tower_platform_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oForwardVel); diff --git a/src/game/behaviors/tuxie.inc.c b/src/game/behaviors/tuxie.inc.c index 7e80ee80..280d1318 100644 --- a/src/game/behaviors/tuxie.inc.c +++ b/src/game/behaviors/tuxie.inc.c @@ -147,7 +147,7 @@ void (*sTuxiesMotherActions[])(void) = { tuxies_mother_act_0, tuxies_mother_act_ tuxies_mother_act_2 }; void bhv_tuxies_mother_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oSubAction); @@ -288,7 +288,7 @@ void small_penguin_free_actions(void) { } void bhv_small_penguin_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, 4000.0f); } switch (o->oHeldState) { diff --git a/src/game/behaviors/ukiki.inc.c b/src/game/behaviors/ukiki.inc.c index a8b8a036..2aad4105 100644 --- a/src/game/behaviors/ukiki.inc.c +++ b/src/game/behaviors/ukiki.inc.c @@ -262,7 +262,7 @@ void ukiki_act_run(void) { //! @bug (Ukikispeedia) This function sets forward speed to 0.9 * Mario's //! forward speed, which means ukiki can move at hyperspeed rates. - cur_obj_set_vel_from_mario_vel(20.0f, 0.9f); + cur_obj_set_vel_from_mario_vel(&gMarioStates[0], 20.0f, 0.9f); if (fleeMario) { if (o->oDistanceToMario > o->oUkikiChaseFleeRange) { diff --git a/src/game/behaviors/water_bomb.inc.c b/src/game/behaviors/water_bomb.inc.c index 235a9337..23e99d53 100644 --- a/src/game/behaviors/water_bomb.inc.c +++ b/src/game/behaviors/water_bomb.inc.c @@ -29,11 +29,13 @@ static struct ObjectHitbox sWaterBombHitbox = { * Spawn water bombs targeting mario when he comes in range. */ void bhv_water_bomb_spawner_update(void) { - if (o->oSyncID == 0) { - network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + if (!network_sync_object_initialized(o)) { + struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + so->fullObjectSync = TRUE; + so->maxUpdateRate = 5.0f; + so->keepRandomSeed = TRUE; network_init_object_field(o, &o->oWaterBombSpawnerBombActive); network_init_object_field(o, &o->oWaterBombSpawnerTimeToSpawn); - network_object_settings(o, FALSE, 0, TRUE, NULL); } f32 latDistToMario = 9999; diff --git a/src/game/behaviors/whomp.inc.c b/src/game/behaviors/whomp.inc.c index 50fbf9da..5897c910 100644 --- a/src/game/behaviors/whomp.inc.c +++ b/src/game/behaviors/whomp.inc.c @@ -267,7 +267,7 @@ void (*sWhompActions[])(void) = { // MM void bhv_whomp_loop(void) { - if (o->oSyncID == 0) { + if (!network_sync_object_initialized(o)) { network_init_object(o, 4000.0f); network_init_object_field(o, &o->oAngleVelPitch); network_init_object_field(o, &o->oFaceAnglePitch); diff --git a/src/game/level_update.c b/src/game/level_update.c index db82424e..da308ff9 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -1196,6 +1196,8 @@ s32 update_level(void) { } s32 init_level(void) { + network_on_init_level(); + s32 val4 = 0; set_play_mode(PLAY_MODE_NORMAL); diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index 44309065..857ad82a 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -999,8 +999,8 @@ void cur_obj_change_action(s32 action) { cur_obj_reset_timer_and_subaction(); } -void cur_obj_set_vel_from_mario_vel(f32 f12, f32 f14) { - f32 sp4 = gMarioStates[0].forwardVel; +void cur_obj_set_vel_from_mario_vel(struct MarioState* m, f32 f12, f32 f14) { + f32 sp4 = m->forwardVel; f32 sp0 = f12 * f14; if (sp4 < sp0) { diff --git a/src/game/object_helpers.h b/src/game/object_helpers.h index b45baf98..7fd97d92 100644 --- a/src/game/object_helpers.h +++ b/src/game/object_helpers.h @@ -146,7 +146,7 @@ s32 count_unimportant_objects(void); s32 count_objects_with_behavior(const BehaviorScript *behavior); struct Object *cur_obj_find_nearby_held_actor(const BehaviorScript *behavior, f32 maxDist); void cur_obj_change_action(s32 action); -void cur_obj_set_vel_from_mario_vel(f32 f12,f32 f14); +void cur_obj_set_vel_from_mario_vel(struct MarioState* m, f32 f12,f32 f14); BAD_RETURN(s16) cur_obj_reverse_animation(void); BAD_RETURN(s32) cur_obj_extend_animation_if_at_end(void); s32 cur_obj_check_if_near_animation_end(void); diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 5d7a69fa..57b2bcd9 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -8,6 +8,10 @@ enum NetworkType networkType; static SOCKET gSocket; struct sockaddr_in txAddr; +#define LOADING_LEVEL_THRESHOLD 10 +u8 networkLoadingLevel = 0; +bool networkLevelLoaded = false; + void network_init(enum NetworkType inNetworkType, char* ip, char* port) { networkType = inNetworkType; @@ -29,6 +33,17 @@ void network_init(enum NetworkType inNetworkType, char* ip, char* port) { } } +void network_on_init_level(void) { + networkLoadingLevel = 0; + networkLevelLoaded = false; +} + +void network_on_loaded_level(void) { + if (networkType == NT_CLIENT) { + network_send_reservation_request(); + } +} + void network_send(struct Packet* p) { // sanity checks if (networkType == NT_NONE) { return; } @@ -49,6 +64,12 @@ void network_send(struct Packet* p) { void network_update(void) { if (networkType == NT_NONE) { return; } + if (!networkLevelLoaded) { + if (networkLoadingLevel++ >= LOADING_LEVEL_THRESHOLD) { + networkLevelLoaded = true; + network_on_loaded_level(); + } + } if (gInsidePainting && sCurrPlayMode == PLAY_MODE_CHANGE_LEVEL) { network_update_inside_painting(); @@ -82,6 +103,8 @@ void network_update(void) { case PACKET_COLLECT_STAR: network_receive_collect_star(&p); break; case PACKET_COLLECT_COIN: network_receive_collect_coin(&p); break; case PACKET_COLLECT_ITEM: network_receive_collect_item(&p); break; + case PACKET_RESERVATION_REQUEST: network_receive_reservation_request(&p); break; + case PACKET_RESERVATION: network_receive_reservation(&p); break; default: printf("%s received unknown packet: %d\n", NETWORKTYPESTR, p.buffer[0]); } diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 0c86e39f..872b4526 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -25,6 +25,8 @@ enum PacketType { PACKET_COLLECT_STAR, PACKET_COLLECT_COIN, PACKET_COLLECT_ITEM, + PACKET_RESERVATION_REQUEST, + PACKET_RESERVATION, }; struct Packet { @@ -39,6 +41,7 @@ struct Packet { struct SyncObject { struct Object* o; + u16 reserved; float maxSyncDistance; bool owned; clock_t clockSinceUpdate; @@ -58,12 +61,14 @@ extern u8 gInsidePainting; extern s16 sCurrPlayMode; extern enum NetworkType networkType; extern struct SyncObject syncObjects[]; +extern bool networkLevelLoaded; void network_init(enum NetworkType inNetworkType, char* ip, char* port); +void network_on_init_level(void); +void network_on_loaded_level(void); void network_clear_sync_objects(void); -void network_init_object(struct Object *object, float maxSyncDistance); -void network_object_settings(struct Object *object, bool fullObjectSync, float maxUpdateRate, bool keepRandomSeed, u8 ignore_if_true(struct Object*)); +struct SyncObject* network_init_object(struct Object *object, float maxSyncDistance); void network_send(struct Packet* p); void network_update(void); void network_shutdown(void); @@ -85,6 +90,8 @@ void network_update_player(void); void network_receive_player(struct Packet* p); bool network_owns_object(struct Object* o); +void network_set_sync_id(struct Object* o); +bool network_sync_object_initialized(struct Object* o); void network_update_objects(void); void network_send_object(struct Object* o); void network_receive_object(struct Packet* p); @@ -109,4 +116,10 @@ void network_receive_collect_coin(struct Packet* p); void network_send_collect_item(struct Object* o); void network_receive_collect_item(struct Packet* p); + +void network_send_reservation_request(void); +void network_receive_reservation_request(struct Packet* p); +void network_send_reservation(void); +void network_receive_reservation(struct Packet* p); + #endif diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index d95aaf45..63f9bfbc 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -28,22 +28,32 @@ void network_clear_sync_objects(void) { nextSyncID = 1; } -void network_init_object(struct Object *o, float maxSyncDistance) { - // generate new sync ID - if (o->oSyncID == 0) { - for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { - if (syncObjects[nextSyncID].o == NULL) { break; } - nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS; - } - assert(syncObjects[nextSyncID].o == NULL); - o->oSyncID = nextSyncID; +void network_set_sync_id(struct Object* o) { + if (o->oSyncID != 0) { return; } + + // two-player hack + u8 reserveId = (networkLevelLoaded && networkType == NT_CLIENT) ? 1 : 0; + + for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { + if (syncObjects[nextSyncID].reserved == reserveId && syncObjects[nextSyncID].o == NULL) { break; } nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS; } + assert(syncObjects[nextSyncID].o == NULL); + assert(syncObjects[nextSyncID].reserved == reserveId); + o->oSyncID = nextSyncID; + nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS; + assert(o->oSyncID < MAX_SYNC_OBJECTS); +} + +struct SyncObject* network_init_object(struct Object *o, float maxSyncDistance) { + // generate new sync ID + network_set_sync_id(o); // set default values for sync object struct SyncObject* so = &syncObjects[o->oSyncID]; so->o = o; + so->reserved = 0; so->maxSyncDistance = maxSyncDistance; so->owned = false; so->clockSinceUpdate = clock(); @@ -56,16 +66,8 @@ void network_init_object(struct Object *o, float maxSyncDistance) { so->ignore_if_true = NULL; so->syncDeathEvent = true; memset(so->extraFields, 0, sizeof(void*) * MAX_SYNC_OBJECT_FIELDS); -} -void network_object_settings(struct Object *o, bool fullObjectSync, float maxUpdateRate, bool keepRandomSeed, u8 ignore_if_true(struct Object*)) { - assert(o->oSyncID != 0); - // override default settings for sync object - struct SyncObject* so = &syncObjects[o->oSyncID]; - so->fullObjectSync = fullObjectSync; - so->maxUpdateRate = maxUpdateRate; - so->keepRandomSeed = keepRandomSeed; - so->ignore_if_true = ignore_if_true; + return so; } void network_init_object_field(struct Object *o, void* field) { @@ -82,6 +84,12 @@ bool network_owns_object(struct Object* o) { return so->owned; } +bool network_sync_object_initialized(struct Object* o) { + if (o->oSyncID == 0) { return false; } + if (syncObjects[o->oSyncID].behavior == NULL) { return false; } + return true; +} + // ----- header ----- // static void packet_write_object_header(struct Packet* p, struct Object* o) { @@ -256,6 +264,7 @@ static void packet_read_object_only_death(struct Packet* p, struct Object* o) { void network_send_object(struct Object* o) { // sanity check SyncObject + if (!network_sync_object_initialized(o)) { return; } struct SyncObject* so = &syncObjects[o->oSyncID]; if (so == NULL) { return; } if (o->behavior != so->behavior) { @@ -299,6 +308,7 @@ void network_receive_object(struct Packet* p) { struct SyncObject* so = packet_read_object_header(p); if (so == NULL) { return; } struct Object* o = so->o; + if (!network_sync_object_initialized(o)) { return; } // make sure no one can update an object we're holding if (gMarioStates[0].heldObj == o) { return; } @@ -324,6 +334,8 @@ bool should_own_object(struct SyncObject* so) { void forget_sync_object(struct SyncObject* so) { so->o = NULL; + so->behavior = NULL; + so->reserved = 0; so->owned = false; } diff --git a/src/pc/network/packets/packet_reservation.c b/src/pc/network/packets/packet_reservation.c new file mode 100644 index 00000000..edc92367 --- /dev/null +++ b/src/pc/network/packets/packet_reservation.c @@ -0,0 +1,72 @@ +#include +#include "../network.h" +#include "object_fields.h" +#include "object_constants.h" +#include "behavior_table.h" +#include "course_table.h" +#include "src/game/interaction.h" +#include "src/engine/math_util.h" + +#define RESERVATION_COUNT 10 + +void network_send_reservation_request(void) { + assert(networkType == NT_CLIENT); + + struct Packet p; + packet_init(&p, PACKET_RESERVATION_REQUEST, true); + network_send(&p); +} + +void network_receive_reservation_request(struct Packet* p) { + assert(networkType == NT_SERVER); + network_send_reservation(); +} + +void network_send_reservation(void) { + assert(networkType == NT_SERVER); + int clientPlayerIndex = 1; // two-player hack + + // find all reserved objects + u8 reservedObjs[RESERVATION_COUNT] = { 0 }; + int reservedIndex = 0; + for (int i = 1; i < MAX_SYNC_OBJECTS; i++) { + if (syncObjects[i].reserved == clientPlayerIndex) { + reservedObjs[reservedIndex++] = i; + if (reservedIndex >= RESERVATION_COUNT) { break; } + } + } + + if (reservedIndex < RESERVATION_COUNT) { + // reserve the rest + for (int i = MAX_SYNC_OBJECTS - 1; i > 0; i--) { + if (syncObjects[i].o != NULL) { continue; } + if (syncObjects[i].reserved != 0) { continue; } + syncObjects[i].reserved = clientPlayerIndex; + reservedObjs[reservedIndex++] = i; + if (reservedIndex >= RESERVATION_COUNT) { break; } + } + } + + struct Packet p; + packet_init(&p, PACKET_RESERVATION, true); + packet_write(&p, reservedObjs, sizeof(u8) * RESERVATION_COUNT); + network_send(&p); +} + +void network_receive_reservation(struct Packet* p) { + assert(networkType == NT_CLIENT); + int clientPlayerIndex = 1; // two-player hack + + // find all reserved objects + u8 reservedObjs[RESERVATION_COUNT] = { 0 }; + packet_read(p, reservedObjs, sizeof(u8) * RESERVATION_COUNT); + + for (int i = 0; i < RESERVATION_COUNT; i++) { + int index = reservedObjs[i]; + printf(" %d", index); + if (index == 0) { continue; } + if (syncObjects[index].o != NULL) { continue; } + syncObjects[index].reserved = clientPlayerIndex; + } + printf("\n"); +} diff --git a/src/pc/network/packets/packet_spawn_objects.c b/src/pc/network/packets/packet_spawn_objects.c index dd880d26..df85d5ec 100644 --- a/src/pc/network/packets/packet_spawn_objects.c +++ b/src/pc/network/packets/packet_spawn_objects.c @@ -56,7 +56,6 @@ void network_send_spawn_objects(struct Object* objects[], u32 models[], u8 objec packet_write(&p, &behaviorId, sizeof(enum BehaviorId)); packet_write(&p, &o->activeFlags, sizeof(s16)); packet_write(&p, o->rawData.asU32, sizeof(s32) * 80); - assert(o->oSyncID == 0); } network_send(&p); @@ -83,6 +82,10 @@ void network_receive_spawn_objects(struct Packet* p) { remoteSpawnIds[onRemoteSpawnId] = remoteSpawnId; onRemoteSpawnId = (onRemoteSpawnId + 1) % MAX_REMOTE_SPAWN_IDS; + // two-player hack + u8 reserveId = (networkLevelLoaded && networkType == NT_SERVER) ? 1 : 0; + bool receivedReservedSyncObject = false; + struct Object* spawned[MAX_SPAWN_OBJECTS_PER_PACKET] = { 0 }; for (u8 i = 0; i < objectCount; i++) { struct SpawnObjectData data = { 0 }; @@ -101,6 +104,18 @@ void network_receive_spawn_objects(struct Packet* p) { struct Object* o = spawn_object(parentObj, data.model, behavior); memcpy(o->rawData.asU32, data.rawData, sizeof(u32) * 80); + // they've allocated one of their reserved sync objects + if (o->oSyncID != 0 && syncObjects[o->oSyncID].reserved == reserveId) { + syncObjects[o->oSyncID].o = o; + syncObjects[o->oSyncID].reserved = 0; + receivedReservedSyncObject = true; + } + spawned[i] = o; } + + // update their block of reserved ids + if (networkType == NT_SERVER && receivedReservedSyncObject) { + network_send_reservation(); + } }