From 2daa6edaa44a97a8543d777b4cc04423358710ff Mon Sep 17 00:00:00 2001 From: MysterD Date: Sun, 26 Mar 2023 21:10:38 -0700 Subject: [PATCH] Deterministically set the sync ID for level objects that spawn from spawninfo, macros, and special --- src/engine/level_script.c | 13 ++++ src/game/area.h | 1 + src/game/macro_special_objects.c | 78 ++++++++++++------- src/game/macro_special_objects.h | 6 +- src/game/object_list_processor.c | 6 ++ src/pc/controller/controller_keyboard_debug.c | 15 ++-- src/pc/network/packets/packet_debug_sync.c | 13 ++-- src/pc/network/sync_object.c | 4 +- src/pc/network/syncid.h | 8 ++ 9 files changed, 102 insertions(+), 42 deletions(-) create mode 100644 src/pc/network/syncid.h diff --git a/src/engine/level_script.c b/src/engine/level_script.c index edbd932b..2020406c 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -430,6 +430,7 @@ static void level_cmd_begin_area(void) { gAreas[areaIndex].unk04 = screenArea; gAreas[areaIndex].numRedCoins = 0; gAreas[areaIndex].numSecrets = 0; + gAreas[areaIndex].nextSyncID = 10; if (node != NULL) { gAreas[areaIndex].camera = (struct Camera *) node->config.camera; @@ -516,6 +517,7 @@ static void level_cmd_init_mario(void) { spawnInfo->behaviorScript = behaviorScript; spawnInfo->unk18 = unk18; spawnInfo->next = NULL; + spawnInfo->syncID = 0; if (lastSpawnInfo != NULL) { lastSpawnInfo->next = spawnInfo; @@ -551,6 +553,9 @@ static void level_cmd_place_object(void) { spawnInfo->unk18 = gLoadedGraphNodes[model]; spawnInfo->next = gAreas[sCurrAreaIndex].objectSpawnInfos; + spawnInfo->syncID = gAreas[sCurrAreaIndex].nextSyncID; + gAreas[sCurrAreaIndex].nextSyncID += 10; + gAreas[sCurrAreaIndex].objectSpawnInfos = spawnInfo; area_check_red_coin_or_secret(spawnInfo->behaviorScript, false); } @@ -947,6 +952,10 @@ static void level_cmd_place_object_ext(void) { spawnInfo->unk18 = gLoadedGraphNodes[model]; spawnInfo->next = gAreas[sCurrAreaIndex].objectSpawnInfos; + spawnInfo->syncID = spawnInfo->next + ? spawnInfo->next->syncID + 10 + : 10; + gAreas[sCurrAreaIndex].objectSpawnInfos = spawnInfo; area_check_red_coin_or_secret(spawnInfo->behaviorScript, false); } @@ -1013,6 +1022,10 @@ static void level_cmd_place_object_ext2(void) { spawnInfo->unk18 = gLoadedGraphNodes[smlua_model_util_load_with_pool(modelId, sLevelPool)]; spawnInfo->next = gAreas[sCurrAreaIndex].objectSpawnInfos; + spawnInfo->syncID = spawnInfo->next + ? spawnInfo->next->syncID + 10 + : 10; + gAreas[sCurrAreaIndex].objectSpawnInfos = spawnInfo; area_check_red_coin_or_secret(spawnInfo->behaviorScript, false); } diff --git a/src/game/area.h b/src/game/area.h index 276089bb..d3e81975 100644 --- a/src/game/area.h +++ b/src/game/area.h @@ -86,6 +86,7 @@ struct Area /*????*/ u8 *macroObjectsAltered; /*????*/ u8 numRedCoins; /*????*/ u8 numSecrets; + /*????*/ u32 nextSyncID; }; // All the transition data to be used in screen_transition.c diff --git a/src/game/macro_special_objects.c b/src/game/macro_special_objects.c index 4531f740..1a55e911 100644 --- a/src/game/macro_special_objects.c +++ b/src/game/macro_special_objects.c @@ -10,7 +10,7 @@ #include "macro_presets.h" #include "special_presets.h" - +#include "src/pc/network/sync_object.h" /* * Converts the rotation value supplied by macro objects into one * that can be used by in-game objects. @@ -43,14 +43,16 @@ s16 convert_rotation(s16 inRotation) { * parameters filling up the upper 2 bytes of newObj->oBehParams. * The object will not spawn if 'behavior' is NULL. */ -void spawn_macro_abs_yrot_2params(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 params) { +struct Object* spawn_macro_abs_yrot_2params(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 params) { if (behavior != NULL) { struct Object *newObj = spawn_object_abs_with_rot( &gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, convert_rotation(ry), 0); if (newObj != NULL) { newObj->oBehParams = ((u32) params) << 16; } + return newObj; } + return NULL; } /* @@ -58,30 +60,34 @@ void spawn_macro_abs_yrot_2params(s32 model, const BehaviorScript *behavior, s16 * a single parameter filling up the upper byte of newObj->oBehParams. * The object will not spawn if 'behavior' is NULL. */ -void spawn_macro_abs_yrot_param1(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 param) { +struct Object* spawn_macro_abs_yrot_param1(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 param) { if (behavior != NULL) { struct Object *newObj = spawn_object_abs_with_rot( &gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, convert_rotation(ry), 0); if (newObj != NULL) { newObj->oBehParams = ((u32) param) << 24; } + return newObj; } + return NULL; } /* * Spawns an object at an absolute location with currently 3 unknown variables that get converted to * floats. Oddly enough, this function doesn't care if 'behavior' is NULL or not. */ -void spawn_macro_abs_special(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 unkA, s16 unkB, +struct Object* spawn_macro_abs_special(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 unkA, s16 unkB, s16 unkC) { struct Object *newObj = spawn_object_abs_with_rot(&gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, 0, 0); - if (newObj == NULL) { return; } + if (newObj == NULL) { return NULL; } // Are all three of these values unused? newObj->oMacroUnk108 = (f32) unkA; newObj->oMacroUnk10C = (f32) unkB; newObj->oMacroUnk110 = (f32) unkC; + + return newObj; } static void spawn_macro_coin_unknown(const BehaviorScript *behavior, s16 a1[]) { @@ -174,8 +180,12 @@ void spawn_macro_objects(s16 areaIndex, s16 *macroObjList) { newObj->respawnInfoType = RESPAWN_INFO_TYPE_16; newObj->respawnInfo = macroObjList - 1; newObj->parentObj = newObj; + newObj->oSyncID = gAreas[areaIndex].nextSyncID; + sync_object_set_id(newObj); } } + + gAreas[areaIndex].nextSyncID += 10; } } @@ -209,39 +219,47 @@ void spawn_macro_objects_hardcoded(s16 areaIndex, s16 *macroObjList) { // Spawn objects based on hardcoded presets, and most seem to be for Big Boo's Haunt. // However, BBH doesn't use this function so this might just be an early test? + struct Object* obj = NULL; switch (macroObjPreset) { case 0: - spawn_macro_abs_yrot_2params(MODEL_NONE, bhvBooBossSpawnedBridge, macroObjX, macroObjY, - macroObjZ, macroObjRY, 0); + obj = spawn_macro_abs_yrot_2params(MODEL_NONE, bhvBooBossSpawnedBridge, macroObjX, macroObjY, + macroObjZ, macroObjRY, 0); break; case 1: - spawn_macro_abs_yrot_2params(MODEL_BBH_TILTING_FLOOR_PLATFORM, - bhvBbhTiltingTrapPlatform, macroObjX, macroObjY, macroObjZ, - macroObjRY, 0); + obj = spawn_macro_abs_yrot_2params(MODEL_BBH_TILTING_FLOOR_PLATFORM, + bhvBbhTiltingTrapPlatform, macroObjX, macroObjY, macroObjZ, + macroObjRY, 0); break; case 2: - spawn_macro_abs_yrot_2params(MODEL_BBH_TUMBLING_PLATFORM, bhvBbhTumblingBridge, - macroObjX, macroObjY, macroObjZ, macroObjRY, 0); + obj = spawn_macro_abs_yrot_2params(MODEL_BBH_TUMBLING_PLATFORM, bhvBbhTumblingBridge, + macroObjX, macroObjY, macroObjZ, macroObjRY, 0); break; case 3: - spawn_macro_abs_yrot_2params(MODEL_BBH_MOVING_BOOKSHELF, bhvHauntedBookshelf, macroObjX, - macroObjY, macroObjZ, macroObjRY, 0); + obj = spawn_macro_abs_yrot_2params(MODEL_BBH_MOVING_BOOKSHELF, bhvHauntedBookshelf, macroObjX, + macroObjY, macroObjZ, macroObjRY, 0); break; case 4: - spawn_macro_abs_yrot_2params(MODEL_BBH_MESH_ELEVATOR, bhvMeshElevator, macroObjX, - macroObjY, macroObjZ, macroObjRY, 0); + obj = spawn_macro_abs_yrot_2params(MODEL_BBH_MESH_ELEVATOR, bhvMeshElevator, macroObjX, + macroObjY, macroObjZ, macroObjRY, 0); break; case 20: - spawn_macro_abs_yrot_2params(MODEL_YELLOW_COIN, bhvYellowCoin, macroObjX, macroObjY, - macroObjZ, macroObjRY, 0); + obj = spawn_macro_abs_yrot_2params(MODEL_YELLOW_COIN, bhvYellowCoin, macroObjX, macroObjY, + macroObjZ, macroObjRY, 0); break; case 21: - spawn_macro_abs_yrot_2params(MODEL_YELLOW_COIN, bhvYellowCoin, macroObjX, macroObjY, - macroObjZ, macroObjRY, 0); + obj = spawn_macro_abs_yrot_2params(MODEL_YELLOW_COIN, bhvYellowCoin, macroObjX, macroObjY, + macroObjZ, macroObjRY, 0); break; default: break; } + + if (obj != NULL) { + obj->oSyncID = gAreas[areaIndex].nextSyncID; + sync_object_set_id(obj); + } + + gAreas[areaIndex].nextSyncID += 10; } } @@ -292,21 +310,22 @@ void spawn_special_objects(s16 areaIndex, s16 **specialObjList) { type = SpecialObjectPresets[offset].type; defaultParam = SpecialObjectPresets[offset].defParam; + struct Object* obj = NULL; switch (type) { case SPTYPE_NO_YROT_OR_PARAMS: - spawn_macro_abs_yrot_2params(model, behavior, x, y, z, 0, 0); + obj = spawn_macro_abs_yrot_2params(model, behavior, x, y, z, 0, 0); break; case SPTYPE_YROT_NO_PARAMS: extraParams[0] = **specialObjList; // Y-rotation (*specialObjList)++; - spawn_macro_abs_yrot_2params(model, behavior, x, y, z, extraParams[0], 0); + obj = spawn_macro_abs_yrot_2params(model, behavior, x, y, z, extraParams[0], 0); break; case SPTYPE_PARAMS_AND_YROT: extraParams[0] = **specialObjList; // Y-rotation (*specialObjList)++; extraParams[1] = **specialObjList; // Params (*specialObjList)++; - spawn_macro_abs_yrot_2params(model, behavior, x, y, z, extraParams[0], extraParams[1]); + obj = spawn_macro_abs_yrot_2params(model, behavior, x, y, z, extraParams[0], extraParams[1]); break; case SPTYPE_UNKNOWN: extraParams[0] = @@ -318,17 +337,24 @@ void spawn_special_objects(s16 areaIndex, s16 **specialObjList) { extraParams[2] = **specialObjList; // Unknown, gets put into obj->oMacroUnk110 as a float (*specialObjList)++; - spawn_macro_abs_special(model, behavior, x, y, z, extraParams[0], extraParams[1], - extraParams[2]); + obj = spawn_macro_abs_special(model, behavior, x, y, z, extraParams[0], extraParams[1], + extraParams[2]); break; case SPTYPE_DEF_PARAM_AND_YROT: extraParams[0] = **specialObjList; // Y-rotation (*specialObjList)++; - spawn_macro_abs_yrot_param1(model, behavior, x, y, z, extraParams[0], defaultParam); + obj = spawn_macro_abs_yrot_param1(model, behavior, x, y, z, extraParams[0], defaultParam); break; default: break; } + + if (obj != NULL) { + obj->oSyncID = gAreas[areaIndex].nextSyncID; + sync_object_set_id(obj); + } + + gAreas[areaIndex].nextSyncID += 10; } } diff --git a/src/game/macro_special_objects.h b/src/game/macro_special_objects.h index 4143f4a7..1ca62007 100644 --- a/src/game/macro_special_objects.h +++ b/src/game/macro_special_objects.h @@ -7,9 +7,9 @@ s16 convert_rotation(s16 inRotation); -void spawn_macro_abs_yrot_2params(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 params); -void spawn_macro_abs_yrot_param1(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 params); -void spawn_macro_abs_special(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 unkA, s16 unkB, s16 unkC); +struct Object* spawn_macro_abs_yrot_2params(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 params); +struct Object* spawn_macro_abs_yrot_param1(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 params); +struct Object* spawn_macro_abs_special(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 unkA, s16 unkB, s16 unkC); void spawn_macro_objects(s16 areaIndex, s16 *macroObjList); void spawn_macro_objects_hardcoded(s16 areaIndex, s16 *macroObjList); diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 5e29f3c7..0984d75b 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -554,6 +554,12 @@ void spawn_objects_from_info(UNUSED s32 unused, struct SpawnInfo *spawnInfo) { object->behavior = smlua_override_behavior(script); object->unused1 = 0; + // set the sync id + if (spawnInfo->syncID) { + object->oSyncID = spawnInfo->syncID; + sync_object_set_id(object); + } + // Record death/collection in the SpawnInfo object->respawnInfoType = RESPAWN_INFO_TYPE_32; object->respawnInfo = &spawnInfo->behaviorArg; diff --git a/src/pc/controller/controller_keyboard_debug.c b/src/pc/controller/controller_keyboard_debug.c index e5bdc094..3e4742ac 100644 --- a/src/pc/controller/controller_keyboard_debug.c +++ b/src/pc/controller/controller_keyboard_debug.c @@ -32,6 +32,8 @@ static bool sHoldingShift = false; #define SCANCODE_ALT 0x38 #define SCANCODE_SHIFT 0x2A +extern void print_sync_object_table(void); + static void debug_breakpoint_here(void) { // create easy breakpoint position for debugging } @@ -103,12 +105,13 @@ void debug_keyboard_on_key_down(int scancode) { case SCANCODE_ALT: sHoldingAlt = true; break; case SCANCODE_SHIFT: sHoldingShift = true; break; case SCANCODE_3: debug_breakpoint_here(); break; - case SCANCODE_1: if (sHoldingAlt) { debug_warp_level1(); } break; - case SCANCODE_2: if (sHoldingAlt) { debug_warp_level2(); } break; - case SCANCODE_4: if (sHoldingAlt) { debug_warp_level3(); } break; - case SCANCODE_8: if (sHoldingAlt) { debug_spawn_object(); } break; - case SCANCODE_9: if (sHoldingAlt) { debug_warp_to(); } break; - case SCANCODE_0: if (sHoldingAlt) { debug_suicide(); } break; + case SCANCODE_1: if (sHoldingAlt) { debug_warp_level1(); } break; + case SCANCODE_2: if (sHoldingAlt) { debug_warp_level2(); } break; + case SCANCODE_4: if (sHoldingAlt) { debug_warp_level3(); } break; + case SCANCODE_5: if (sHoldingAlt) { print_sync_object_table(); } break; + case SCANCODE_8: if (sHoldingAlt) { debug_spawn_object(); } break; + case SCANCODE_9: if (sHoldingAlt) { debug_warp_to(); } break; + case SCANCODE_0: if (sHoldingAlt) { debug_suicide(); } break; case SCANCODE_F5: debug_reload_lua(); break; } } diff --git a/src/pc/network/packets/packet_debug_sync.c b/src/pc/network/packets/packet_debug_sync.c index 8e695c73..d83c3f35 100644 --- a/src/pc/network/packets/packet_debug_sync.c +++ b/src/pc/network/packets/packet_debug_sync.c @@ -2,12 +2,15 @@ #include "behavior_table.h" #include "pc/debuglog.h" -static void print_sync_object_table(void) { +void print_sync_object_table(void) { LOG_INFO("Sync Object Table"); - for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { + for (u32 i = 0; i < SYNC_ID_BLOCK_SIZE * (MAX_PLAYERS + 1); i++) { + struct SyncObject* so = sync_object_get(i); if (!so || !so->o) { continue; } u32 behaviorId = get_id_from_behavior(so->behavior); - LOG_INFO("%03d: %08X", so->id, behaviorId); + char* behaviorName = (char*)get_behavior_name_from_id(behaviorId); + if (!behaviorName) { behaviorName = "UNKNOWN"; } + LOG_INFO("%04d: %08X :: %s", so->id, behaviorId, behaviorName); behaviorId = behaviorId; // suppress warning } LOG_INFO(" "); @@ -37,7 +40,7 @@ void network_receive_debug_sync(struct Packet* p) { struct SyncObject* so = sync_object_get(id); if (!so) { - LOG_INFO("Sync Table Missing: %03d : %08X :: %s", id, behaviorId, behaviorName); + LOG_INFO("Sync Table Missing: %04d : %08X :: %s", id, behaviorId, behaviorName); return; } @@ -46,7 +49,7 @@ void network_receive_debug_sync(struct Packet* p) { if (!localBehaviorName) { localBehaviorName = "UNKNOWN"; } if (localBehaviorId != behaviorId) { - LOG_INFO("Sync Table MisMatch: %03d : %08X != %08X :: (%s != %s)", id, localBehaviorId, behaviorId, localBehaviorName, behaviorName); + LOG_INFO("Sync Table MisMatch: %04d : %08X != %08X :: (%s != %s)", id, localBehaviorId, behaviorId, localBehaviorName, behaviorName); return; } diff --git a/src/pc/network/sync_object.c b/src/pc/network/sync_object.c index c260285c..aa8de6be 100644 --- a/src/pc/network/sync_object.c +++ b/src/pc/network/sync_object.c @@ -27,7 +27,7 @@ struct SyncObjectForgetEntry { }; struct SyncObjectForgetEntry* sForgetList = NULL; -static u32 sNextSyncId = 0; +static u32 sNextSyncId = SYNC_ID_BLOCK_SIZE / 2; static u32 sIterateIndex = 0; static bool sFreeingAll = false; @@ -72,7 +72,7 @@ void sync_objects_update(void) { } void sync_objects_clear(void) { - sNextSyncId = 0; + sNextSyncId = SYNC_ID_BLOCK_SIZE / 2; network_on_init_area(); sFreeingAll = true; diff --git a/src/pc/network/syncid.h b/src/pc/network/syncid.h new file mode 100644 index 00000000..d62ba292 --- /dev/null +++ b/src/pc/network/syncid.h @@ -0,0 +1,8 @@ +#ifndef SYNCID_H +#define SYNCID_H + +struct SyncIdPool { + +}; + +#endif \ No newline at end of file