diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index e7ea4895..3cf25695 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -3994,6 +3994,7 @@ + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index fc59e122..03d2e65b 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -15141,6 +15141,9 @@ Source Files\src\pc\network + + Source Files\src\pc\network\packets + diff --git a/include/object_fields.h b/include/object_fields.h index 0bfed252..e01c87fe 100644 --- a/include/object_fields.h +++ b/include/object_fields.h @@ -376,6 +376,7 @@ #define /*0x0F8*/ oCheckerBoardPlatformUnkF8 OBJECT_FIELD_S32(0x1C) // oAction like #define /*0x0FC*/ oCheckerBoardPlatformUnkFC OBJECT_FIELD_S32(0x1D) #define /*0x1AC*/ oCheckerBoardPlatformUnk1AC OBJECT_FIELD_F32(0x49) +#define /*0x1B0*/ oCheckerBoardPlatformTimer OBJECT_FIELD_U32(0x4A) /* Cheep Cheep */ #define /*0x0F4*/ oCheepCheepUnkF4 OBJECT_FIELD_F32(0x1B) diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index 6f52f6bd..34c9131c 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -1052,3 +1052,68 @@ void cur_obj_update(void) { } } } + +// Execute the behavior script of the current object, process the object flags, and other miscellaneous code for updating objects. +void cur_obj_fake_update(void) { + UNUSED u32 unused; + + s16 objFlags = gCurrentObject->oFlags; + + // Increment the object's timer. + if (gCurrentObject->oTimer < 0x3FFFFFFF) { + gCurrentObject->oTimer++; + } + + // If the object's action has changed, reset the action timer. + if (gCurrentObject->oAction != gCurrentObject->oPrevAction) { + (void) (gCurrentObject->oTimer = 0, gCurrentObject->oSubAction = 0, + gCurrentObject->oPrevAction = gCurrentObject->oAction); + } + + // Execute various code based on object flags. + objFlags = (s16) gCurrentObject->oFlags; + + if (objFlags & OBJ_FLAG_SET_FACE_ANGLE_TO_MOVE_ANGLE) { + obj_set_face_angle_to_move_angle(gCurrentObject); + } + + if (objFlags & OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW) { + gCurrentObject->oFaceAngleYaw = gCurrentObject->oMoveAngleYaw; + } + + if (objFlags & OBJ_FLAG_MOVE_XZ_USING_FVEL) { + cur_obj_move_xz_using_fvel_and_yaw(); + } + + if (objFlags & OBJ_FLAG_MOVE_Y_WITH_TERMINAL_VEL) { + cur_obj_move_y_with_terminal_vel(); + } + + if (objFlags & OBJ_FLAG_TRANSFORM_RELATIVE_TO_PARENT) { + obj_build_transform_relative_to_parent(gCurrentObject); + } + + if (objFlags & OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM) { + obj_set_throw_matrix_from_transform(gCurrentObject); + } + + if (objFlags & OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE) { + obj_update_gfx_pos_and_angle(gCurrentObject); + } + + // Calculate the distance from the object to Mario. + if (objFlags & OBJ_FLAG_COMPUTE_DIST_TO_MARIO) { + gCurrentObject->oDistanceToMario = dist_between_objects(gCurrentObject, gMarioObject); + } + + // Calculate the angle from the object to Mario. + if (objFlags & OBJ_FLAG_COMPUTE_ANGLE_TO_MARIO) { + gCurrentObject->oAngleToMario = obj_angle_to_object(gCurrentObject, gMarioObject); + } + + // If the object's action has changed, reset the action timer. + if (gCurrentObject->oAction != gCurrentObject->oPrevAction) { + (void)(gCurrentObject->oTimer = 0, gCurrentObject->oSubAction = 0, + gCurrentObject->oPrevAction = gCurrentObject->oAction); + } +} diff --git a/src/engine/behavior_script.h b/src/engine/behavior_script.h index 92ba1099..98ccfd63 100644 --- a/src/engine/behavior_script.h +++ b/src/engine/behavior_script.h @@ -26,5 +26,6 @@ s32 random_sign(void); void stub_behavior_script_2(void); void cur_obj_update(void); +void cur_obj_fake_update(void); #endif // BEHAVIOR_SCRIPT_H diff --git a/src/game/behaviors/bowser_puzzle_piece.inc.c b/src/game/behaviors/bowser_puzzle_piece.inc.c index 088074fd..a8573e4b 100644 --- a/src/game/behaviors/bowser_puzzle_piece.inc.c +++ b/src/game/behaviors/bowser_puzzle_piece.inc.c @@ -260,15 +260,15 @@ void (*sBowserPuzzlePieceActions[])(void) = { void bhv_lll_bowser_puzzle_piece_loop(void) { // make sure we're loaded and synchronized - if (!gNetworkLevelLoaded) { + if (!gNetworkAreaLoaded) { o->oTimer = 0; return; - } else if (o->oBowserPuzzlePieceTimer == 0 && (gNetworkLevelTimer - o->oBowserPuzzlePieceTimer) >= 650) { - o->oBowserPuzzlePieceTimer = ((gNetworkLevelTimer - o->oBowserPuzzlePieceTimer) / 650) * 650; + } else if (o->oBowserPuzzlePieceTimer == 0 && (gNetworkAreaTimer - o->oBowserPuzzlePieceTimer) >= 650) { + o->oBowserPuzzlePieceTimer = ((gNetworkAreaTimer - o->oBowserPuzzlePieceTimer) / 650) * 650; o->oTimer = 0; } - while (o->oBowserPuzzlePieceTimer < gNetworkLevelTimer) { + while (o->oBowserPuzzlePieceTimer < gNetworkAreaTimer) { bhv_lll_bowser_puzzle_piece_update(); cur_obj_call_action_function(sBowserPuzzlePieceActions); @@ -278,8 +278,8 @@ void bhv_lll_bowser_puzzle_piece_loop(void) { o->oPosZ = o->oBowserPuzzlePieceOffsetZ + o->oHomeZ; o->oBowserPuzzlePieceTimer++; - if (o->oBowserPuzzlePieceTimer < gNetworkLevelTimer) { - o->oTimer++; + if (o->oBowserPuzzlePieceTimer < gNetworkAreaTimer) { + cur_obj_fake_update(); } } } diff --git a/src/game/behaviors/cannon_door.inc.c b/src/game/behaviors/cannon_door.inc.c index b761ea00..18e5b46f 100644 --- a/src/game/behaviors/cannon_door.inc.c +++ b/src/game/behaviors/cannon_door.inc.c @@ -4,7 +4,7 @@ void bhv_cannon_closed_init(void) { struct Object *cannon; if (save_file_is_cannon_unlocked() == 1) { - if (!gNetworkLevelLoaded || gNetworkType == NT_SERVER) { + if (!gNetworkAreaLoaded || gNetworkType == NT_SERVER) { // If the cannon is open, spawn a cannon and despawn the object. cannon = spawn_object(o, MODEL_CANNON_BASE, bhvCannon); cannon->parentObj = cannon; @@ -12,7 +12,7 @@ void bhv_cannon_closed_init(void) { cannon->oPosX = o->oHomeX; cannon->oPosY = o->oHomeY; cannon->oPosZ = o->oHomeZ; - if (gNetworkLevelLoaded) { + if (gNetworkAreaLoaded) { network_set_sync_id(cannon); struct Object* spawn_objects[] = { cannon }; u32 models[] = { MODEL_CANNON_BASE }; diff --git a/src/game/behaviors/chain_chomp.inc.c b/src/game/behaviors/chain_chomp.inc.c index dc00cec4..23b87641 100644 --- a/src/game/behaviors/chain_chomp.inc.c +++ b/src/game/behaviors/chain_chomp.inc.c @@ -528,7 +528,7 @@ void bhv_wooden_post_update(void) { // chomp o->oWoodenPostOffsetY = -190.0f; if (o->parentObj != o) { - if (gNetworkLevelSyncing) { + if (gNetworkAreaSyncing) { // force chain chomp cutscene ending o->parentObj->oAction = CHAIN_CHOMP_ACT_UNLOAD_CHAIN; o->parentObj->oChainChompReleaseStatus = CHAIN_CHOMP_RELEASED_END_CUTSCENE; diff --git a/src/game/behaviors/checkerboard_platform.inc.c b/src/game/behaviors/checkerboard_platform.inc.c index c7e5f7e9..342229d4 100644 --- a/src/game/behaviors/checkerboard_platform.inc.c +++ b/src/game/behaviors/checkerboard_platform.inc.c @@ -5,9 +5,6 @@ struct Struct8032F754 D_8032F754[] = { { 145, { 0.7f, 1.5f, 0.7f }, 7.0f }, void bhv_checkerboard_elevator_group_init(void) { o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; - struct SyncObject* so = network_init_object(o, 1000.0f); - so->hasStandardFields = FALSE; - so->maxUpdateRate = 5.0f; s32 sp3C; s32 sp38; s32 sp34; @@ -26,26 +23,9 @@ void bhv_checkerboard_elevator_group_init(void) { sp2C = spawn_object_relative(i, 0, i * sp3C, sp38, o, MODEL_CHECKERBOARD_PLATFORM, bhvCheckerboardPlatformSub); sp2C->oCheckerBoardPlatformUnk1AC = D_8032F754[sp34].unk2; + sp2C->oTimer = 0; + sp2C->oCheckerBoardPlatformTimer = 0; vec3f_copy_2(sp2C->header.gfx.scale, D_8032F754[sp34].unk1); - - network_init_object_field(o, &sp2C->oMoveAnglePitch); - network_init_object_field(o, &sp2C->oMoveAngleYaw); - network_init_object_field(o, &sp2C->oFaceAnglePitch); - network_init_object_field(o, &sp2C->oFaceAngleYaw); - network_init_object_field(o, &sp2C->oAngleVelPitch); - network_init_object_field(o, &sp2C->oAngleVelYaw); - network_init_object_field(o, &sp2C->oForwardVel); - network_init_object_field(o, &sp2C->oPosX); - network_init_object_field(o, &sp2C->oPosY); - network_init_object_field(o, &sp2C->oPosZ); - network_init_object_field(o, &sp2C->oVelX); - network_init_object_field(o, &sp2C->oVelY); - network_init_object_field(o, &sp2C->oVelZ); - network_init_object_field(o, &sp2C->oAction); - network_init_object_field(o, &sp2C->oPrevAction); - network_init_object_field(o, &sp2C->oTimer); - network_init_object_field(o, &sp2C->oCheckerBoardPlatformUnkF8); - network_init_object_field(o, &sp2C->oCheckerBoardPlatformUnkFC); } } @@ -63,8 +43,9 @@ void checkerboard_plat_act_move_y(UNUSED s32 unused, f32 vel, s32 a2) { void checkerboard_plat_act_rotate(s32 a0, s16 a1) { o->oVelY = 0.0f; o->oAngleVelPitch = a1; - if (o->oTimer + 1 == 0x8000 / absi(a1)) + if (o->oTimer + 1 == 0x8000 / absi(a1)) { o->oAction = a0; + } o->oCheckerBoardPlatformUnkF8 = a0; } @@ -73,42 +54,65 @@ void bhv_checkerboard_platform_init(void) { } void bhv_checkerboard_platform_loop(void) { - f32 sp24 = o->oCheckerBoardPlatformUnk1AC; - o->oCheckerBoardPlatformUnkF8 = 0; + // make sure we're loaded and synchronized + if (!gNetworkAreaLoaded) { + o->oTimer = 0; + o->oCheckerBoardPlatformTimer = 0; + return; + } else { + u32 loopLength = 132 + o->oCheckerBoardPlatformUnkFC * 2; + if (o->oCheckerBoardPlatformTimer == 0 && (gNetworkAreaTimer - o->oCheckerBoardPlatformTimer) >= loopLength) { + o->oTimer = 0; + o->oCheckerBoardPlatformTimer = ((gNetworkAreaTimer - o->oCheckerBoardPlatformTimer) / loopLength) * loopLength; + } + } + if (o->oDistanceToMario < 1000.0f) cur_obj_play_sound_1(SOUND_ENV_ELEVATOR4); - switch (o->oAction) { - case 0: - if (o->oBehParams2ndByte == 0) - o->oAction = 1; - else - o->oAction = 3; - break; - case 1: - checkerboard_plat_act_move_y(2, 10.0f, o->oCheckerBoardPlatformUnkFC); - break; - case 2: - checkerboard_plat_act_rotate(3, 512); - break; - case 3: - checkerboard_plat_act_move_y(4, -10.0f, o->oCheckerBoardPlatformUnkFC); - break; - case 4: - checkerboard_plat_act_rotate(1, -512); - break; + + while (o->oCheckerBoardPlatformTimer < gNetworkAreaTimer) { + s32 oldAction = o->oAction; + f32 sp24 = o->oCheckerBoardPlatformUnk1AC; + o->oCheckerBoardPlatformUnkF8 = 0; + switch (o->oAction) { + case 0: + if (o->oBehParams2ndByte == 0) + o->oAction = 1; + else + o->oAction = 3; + break; + case 1: + checkerboard_plat_act_move_y(2, 10.0f, o->oCheckerBoardPlatformUnkFC); + break; + case 2: + checkerboard_plat_act_rotate(3, 512); + break; + case 3: + checkerboard_plat_act_move_y(4, -10.0f, o->oCheckerBoardPlatformUnkFC); + break; + case 4: + checkerboard_plat_act_rotate(1, -512); + break; + } + o->oMoveAnglePitch += absi(o->oAngleVelPitch); + o->oFaceAnglePitch += absi(o->oAngleVelPitch); + o->oFaceAngleYaw = o->oMoveAngleYaw; + if (o->oMoveAnglePitch != 0) { + o->oForwardVel = signum_positive(o->oAngleVelPitch) * sins(o->oMoveAnglePitch) * sp24; + o->oVelY = signum_positive(o->oAngleVelPitch) * coss(o->oMoveAnglePitch) * sp24; + } + if (o->oCheckerBoardPlatformUnkF8 == 1) { + o->oAngleVelPitch = 0; + o->oFaceAnglePitch &= ~0x7FFF; + cur_obj_move_using_fvel_and_gravity(); + } else + cur_obj_move_using_fvel_and_gravity(); + + o->oCheckerBoardPlatformTimer++; + if (o->oCheckerBoardPlatformTimer < gNetworkAreaTimer) { + cur_obj_fake_update(); + } } - o->oMoveAnglePitch += absi(o->oAngleVelPitch); - o->oFaceAnglePitch += absi(o->oAngleVelPitch); - o->oFaceAngleYaw = o->oMoveAngleYaw; - if (o->oMoveAnglePitch != 0) { - o->oForwardVel = signum_positive(o->oAngleVelPitch) * sins(o->oMoveAnglePitch) * sp24; - o->oVelY = signum_positive(o->oAngleVelPitch) * coss(o->oMoveAnglePitch) * sp24; - } - if (o->oCheckerBoardPlatformUnkF8 == 1) { - o->oAngleVelPitch = 0; - o->oFaceAnglePitch &= ~0x7FFF; - cur_obj_move_using_fvel_and_gravity(); - } else - cur_obj_move_using_fvel_and_gravity(); + load_object_collision_model(); } diff --git a/src/game/behaviors/sparkle_spawn_star.inc.c b/src/game/behaviors/sparkle_spawn_star.inc.c index 4ef83e1a..92d85a74 100644 --- a/src/game/behaviors/sparkle_spawn_star.inc.c +++ b/src/game/behaviors/sparkle_spawn_star.inc.c @@ -24,7 +24,7 @@ void bhv_spawned_star_init(void) { // exclamation box stars are not sent through the normal exclamation box // path due to jankiness in oBehParams. Send the spawn event here instead. u8 spawnedFromExclamationBox = (o->parentObj != NULL && o->parentObj->behavior == bhvExclamationBox); - if (gNetworkLevelLoaded && spawnedFromExclamationBox) { + if (gNetworkAreaLoaded && spawnedFromExclamationBox) { o->parentObj = o; struct Object* spawn_objects[] = { o }; u32 models[] = { MODEL_STAR }; diff --git a/src/pc/controller/controller_keyboard_debug.c b/src/pc/controller/controller_keyboard_debug.c index 484ef042..57d91dcc 100644 --- a/src/pc/controller/controller_keyboard_debug.c +++ b/src/pc/controller/controller_keyboard_debug.c @@ -13,7 +13,7 @@ #ifdef DEBUG -static u8 warpToLevel = LEVEL_LLL; +static u8 warpToLevel = LEVEL_BOB; #define SCANCODE_0 0x0B #define SCANCODE_1 0x02 diff --git a/src/pc/network/network.c b/src/pc/network/network.c index a7deed34..87cdcd01 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -25,9 +25,9 @@ struct NetworkSystem* gNetworkSystem = &gNetworkSystemSocket; #define LOADING_LEVEL_THRESHOLD 10 u16 networkLoadingLevel = 0; -bool gNetworkLevelLoaded = false; -bool gNetworkLevelSyncing = true; -u32 gNetworkLevelTimer = 0; +bool gNetworkAreaLoaded = false; +bool gNetworkAreaSyncing = true; +u32 gNetworkAreaTimer = 0; clock_t gLastNetworkSend = 0; struct StringLinkedList gRegisteredMods = { 0 }; @@ -87,15 +87,15 @@ bool network_init(enum NetworkType inNetworkType) { return true; } -void network_on_init_level(void) { +void network_on_init_area(void) { // reset loading timer networkLoadingLevel = 0; - gNetworkLevelLoaded = false; - gNetworkLevelSyncing = true; - gNetworkLevelTimer = 0; + gNetworkAreaLoaded = false; + gNetworkAreaSyncing = true; + gNetworkAreaTimer = 0; } -void network_on_loaded_level(void) { +void network_on_loaded_area(void) { area_remove_sync_ids_clear(); struct NetworkPlayer* np = gNetworkPlayerLocal; if (np != NULL) { @@ -228,13 +228,13 @@ void network_update(void) { // check for level loaded event if (networkLoadingLevel < LOADING_LEVEL_THRESHOLD) { networkLoadingLevel++; - if (!gNetworkLevelLoaded && networkLoadingLevel >= LOADING_LEVEL_THRESHOLD) { - gNetworkLevelLoaded = true; - gNetworkLevelTimer = 0; - network_on_loaded_level(); + if (!gNetworkAreaLoaded && networkLoadingLevel >= LOADING_LEVEL_THRESHOLD) { + gNetworkAreaLoaded = true; + gNetworkAreaTimer = 0; + network_on_loaded_area(); } - } else if (gNetworkLevelLoaded) { - gNetworkLevelTimer++; + } else if (gNetworkAreaLoaded) { + gNetworkAreaTimer++; } // send out update packets diff --git a/src/pc/network/network.h b/src/pc/network/network.h index cfcaadbb..cba3bfef 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -80,9 +80,9 @@ struct ServerSettings { // Networking-specific externs extern struct NetworkSystem* gNetworkSystem; extern enum NetworkType gNetworkType; -extern bool gNetworkLevelLoaded; -extern bool gNetworkLevelSyncing; -extern u32 gNetworkLevelTimer; +extern bool gNetworkAreaLoaded; +extern bool gNetworkAreaSyncing; +extern u32 gNetworkAreaTimer; extern struct SyncObject gSyncObjects[]; extern struct ServerSettings gServerSettings; extern clock_t gLastNetworkSend; @@ -91,8 +91,8 @@ extern struct StringLinkedList gRegisteredMods; // network.c void network_set_system(enum NetworkSystemType nsType); bool network_init(enum NetworkType inNetworkType); -void network_on_init_level(void); -void network_on_loaded_level(void); +void network_on_init_area(void); +void network_on_loaded_area(void); void network_send_to(u8 localIndex, struct Packet* p); void network_send(struct Packet* p); void network_receive(u8 localIndex, u8* data, u16 dataLength); diff --git a/src/pc/network/packets/packet_area.c b/src/pc/network/packets/packet_area.c index a8f11b68..864373d2 100644 --- a/src/pc/network/packets/packet_area.c +++ b/src/pc/network/packets/packet_area.c @@ -44,7 +44,7 @@ void network_send_area(struct NetworkPlayer* toNp) { packet_write(&p, &gCurrAreaIndex, sizeof(s16)); // area variables - packet_write(&p, &gNetworkLevelTimer, sizeof(u32)); + packet_write(&p, &gNetworkAreaTimer, sizeof(u32)); // write sync id removals packet_write(&p, &sRemoveSyncIdsIndex, sizeof(u8)); @@ -132,16 +132,15 @@ void network_receive_area(struct Packet* p) { packet_read(p, &levelNum, sizeof(s16)); packet_read(p, &areaIndex, sizeof(s16)); - // read area variables - packet_read(p, &gNetworkLevelTimer, sizeof(u32)); - - extern s16 gCurrCourseNum, gCurrActStarNum, gCurrLevelNum; if (courseNum != gCurrCourseNum || actNum != gCurrActStarNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) { LOG_ERROR("rx area: received an improper location"); return; } + // read area variables + packet_read(p, &gNetworkAreaTimer, 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_object.c b/src/pc/network/packets/packet_object.c index 22cca5fa..54fea2b4 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -139,7 +139,7 @@ bool network_sync_object_initialized(struct Object* o) { void network_clear_sync_objects(void) { sNextSyncId = 0; - network_on_init_level(); + network_on_init_area(); for (u16 i = 0; i < MAX_SYNC_OBJECTS; i++) { network_forget_sync_object(&gSyncObjects[i]); } @@ -149,7 +149,7 @@ void network_set_sync_id(struct Object* o) { if (o->oSyncID != 0) { return; } u8 syncId = 0; - if (!gNetworkLevelLoaded) { + if (!gNetworkAreaLoaded) { // while loading, just fill in sync ids from 1 to MAX_SYNC_OBJECTS for (int i = 1; i < MAX_SYNC_OBJECTS; i++) { sNextSyncId++; @@ -168,7 +168,7 @@ void network_set_sync_id(struct Object* o) { o->oSyncID = syncId; - if (gNetworkLevelLoaded) { + if (gNetworkAreaLoaded) { LOG_INFO("set sync id for object w/behavior %d", get_id_from_behavior(o->behavior)); } diff --git a/src/pc/network/packets/packet_sync_valid.c b/src/pc/network/packets/packet_sync_valid.c index 20aeeacc..49ddf1ce 100644 --- a/src/pc/network/packets/packet_sync_valid.c +++ b/src/pc/network/packets/packet_sync_valid.c @@ -10,7 +10,7 @@ void network_send_sync_valid(struct NetworkPlayer* toNp) { if (toNp == gNetworkPlayerLocal) { // the player is the server, no need to send it - gNetworkLevelSyncing = false; + gNetworkAreaSyncing = false; return; } @@ -62,5 +62,5 @@ void network_receive_sync_valid(struct Packet* p) { } // we're no longer syncing - gNetworkLevelSyncing = false; + gNetworkAreaSyncing = false; }