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
This commit is contained in:
MysterD 2020-08-24 18:33:53 -07:00
parent ee35c999aa
commit 8c650a5b7d
39 changed files with 240 additions and 84 deletions

View file

@ -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),

View file

@ -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);

View file

@ -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);

View file

@ -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) {

View file

@ -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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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) {

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -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);
}

View file

@ -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);

View file

@ -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)) {

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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) {

View file

@ -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) {

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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) {

View file

@ -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);

View file

@ -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]);
}

View file

@ -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

View file

@ -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;
}

View file

@ -0,0 +1,72 @@
#include <stdio.h>
#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");
}

View file

@ -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();
}
}