diff --git a/src/game/area.c b/src/game/area.c index d9f81443a..d416233c4 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -229,8 +229,6 @@ void clear_areas(void) { gAreaData[i].dialog[1] = 255; gAreaData[i].musicParam = 0; gAreaData[i].musicParam2 = 0; - memset(gAreaData[i].cachedBehaviors, 0, sizeof(u8) * 256); - memset(gAreaData[i].cachedPositions, 0, sizeof(Vec3f) * 256); } } diff --git a/src/game/area.h b/src/game/area.h index 22ec11185..276089bb8 100644 --- a/src/game/area.h +++ b/src/game/area.h @@ -45,6 +45,7 @@ struct SpawnInfo /*0x14*/ void *behaviorScript; /*0x18*/ struct GraphNode *unk18; /*0x1C*/ struct SpawnInfo *next; + /*0x20*/ u32 syncID; }; struct UnusedArea28 @@ -81,8 +82,6 @@ struct Area /*0x34*/ u8 dialog[2]; // Level start dialog number (set by level script cmd 0x30) /*0x36*/ u16 musicParam; /*0x38*/ u16 musicParam2; - /*????*/ u8 cachedBehaviors[256]; - /*????*/ Vec3f cachedPositions[256]; /*????*/ u32 localAreaTimer; /*????*/ u8 *macroObjectsAltered; /*????*/ u8 numRedCoins; diff --git a/src/pc/controller/controller_keyboard_debug.c b/src/pc/controller/controller_keyboard_debug.c index 72c7d1302..e5bdc0949 100644 --- a/src/pc/controller/controller_keyboard_debug.c +++ b/src/pc/controller/controller_keyboard_debug.c @@ -81,16 +81,20 @@ static void debug_reload_lua(void) { } static void debug_spawn_object(void) { - struct Object* box = spawn_object(gMarioStates[0].marioObj, MODEL_BREAKABLE_BOX_SMALL, bhvBreakableBoxSmall); - if (box == NULL) { return; } - if (!sync_object_set_id(box)) { - box->activeFlags = ACTIVE_FLAG_DEACTIVATED; - return; - } + for (int i = 0; i < 1; i++) { + struct Object* box = spawn_object(gMarioStates[0].marioObj, MODEL_BREAKABLE_BOX_SMALL, bhvBreakableBoxSmall); + if (box == NULL) { return; } + //box->oPosX += (random_float() - 0.5f) * 1000.0f; + //box->oPosZ += (random_float() - 0.5f) * 1000.0f; + if (!sync_object_set_id(box)) { + box->activeFlags = ACTIVE_FLAG_DEACTIVATED; + return; + } - struct Object* spawn_objects[] = { box }; - u32 models[] = { MODEL_BREAKABLE_BOX_SMALL }; - network_send_spawn_objects(spawn_objects, models, 1); + struct Object* spawn_objects[] = { box }; + u32 models[] = { MODEL_BREAKABLE_BOX_SMALL }; + network_send_spawn_objects(spawn_objects, models, 1); + } } void debug_keyboard_on_key_down(int scancode) { diff --git a/src/pc/lua/smlua_cobject_allowlist.c b/src/pc/lua/smlua_cobject_allowlist.c index e1631b9dd..ecd6a166a 100644 --- a/src/pc/lua/smlua_cobject_allowlist.c +++ b/src/pc/lua/smlua_cobject_allowlist.c @@ -1,6 +1,5 @@ #include #include "smlua.h" -#define STB_DS_IMPLEMENTATION 1 #include "pc/utils/stb_ds.h" struct AllowList { diff --git a/src/pc/network/network.c b/src/pc/network/network.c index ea66df4cb..6cb88f279 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -441,6 +441,8 @@ void network_update(void) { packet_ordered_update(); } + sync_objects_update(); + // update level/area request timers /*struct NetworkPlayer* np = gNetworkPlayerLocal; if (np != NULL && !np->currLevelSyncValid) { diff --git a/src/pc/network/packets/packet_area.c b/src/pc/network/packets/packet_area.c index 583d4b376..565f5cc1b 100644 --- a/src/pc/network/packets/packet_area.c +++ b/src/pc/network/packets/packet_area.c @@ -95,9 +95,10 @@ void network_send_area(struct NetworkPlayer* toNp) { network_send_to(toNp->localIndex, &p); // send non-static objects - for (struct SyncObject* so = sync_object_get_first_non_static(); so != NULL; so = sync_object_get_next()) { + for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { if (so == NULL || so->o == NULL || so->o->oSyncID != so->id) { continue; } if (so->o->behavior == smlua_override_behavior(bhvRespawner)) { continue; } + if (so->id < RESERVED_IDS_SYNC_OBJECT_OFFSET) { continue; } struct Object* spawn_objects[] = { so->o }; // TODO: move find model to a utility file/function diff --git a/src/pc/network/packets/packet_debug_sync.c b/src/pc/network/packets/packet_debug_sync.c index 2b8d454a1..8e695c73c 100644 --- a/src/pc/network/packets/packet_debug_sync.c +++ b/src/pc/network/packets/packet_debug_sync.c @@ -14,54 +14,40 @@ static void print_sync_object_table(void) { } void network_send_debug_sync(void) { - u16 objectCount = 0; - for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { - if (!so || !so->o) { continue; } - objectCount++; - } - - struct Packet p = { 0 }; - packet_init(&p, PACKET_DEBUG_SYNC, true, PLMT_AREA); - packet_write(&p, &objectCount, sizeof(u16)); for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { if (!so || !so->o) { continue; } u32 behaviorId = get_id_from_behavior((so->behavior == NULL) ? so->behavior : so->o->behavior); + struct Packet p = { 0 }; + packet_init(&p, PACKET_DEBUG_SYNC, true, PLMT_AREA); packet_write(&p, &so->id, sizeof(u32)); packet_write(&p, &behaviorId, sizeof(u32)); + network_send(&p); } - network_send(&p); } void network_receive_debug_sync(struct Packet* p) { - u16 objectCount = 0; - u32 remoteBehaviorIds[1024] = { 0 }; + u32 id; + u32 behaviorId; - packet_read(p, &objectCount, sizeof(u16)); - for (s32 i = 0; i < objectCount; i++) { - u32 j; - u32 behaviorId; - packet_read(p, &j, sizeof(u32)); - packet_read(p, &behaviorId, sizeof(u32)); - remoteBehaviorIds[j] = behaviorId; + packet_read(p, &id, sizeof(u32)); + packet_read(p, &behaviorId, sizeof(u32)); + + char* behaviorName = (char*)get_behavior_name_from_id(behaviorId); + if (!behaviorName) { behaviorName = "UNKNOWN"; } + + struct SyncObject* so = sync_object_get(id); + if (!so) { + LOG_INFO("Sync Table Missing: %03d : %08X :: %s", id, behaviorId, behaviorName); + return; } - bool hasMismatch = false; - for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { - u32 localBehaviorId = (so && so->o) ? get_id_from_behavior(so->behavior) : 0; - u32 remoteBehaviorId = remoteBehaviorIds[so->id]; - if (localBehaviorId != remoteBehaviorId) { - hasMismatch = true; - break; - } - } - if (!hasMismatch) { return; } + u32 localBehaviorId = get_id_from_behavior((so->behavior == NULL) ? so->behavior : so->o->behavior); + char* localBehaviorName = (char*)get_behavior_name_from_id(localBehaviorId); + if (!localBehaviorName) { localBehaviorName = "UNKNOWN"; } - LOG_INFO(" "); - LOG_INFO("Sync Object Table Mismatch"); - for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { - u32 localBehaviorId = (so && so->o) ? get_id_from_behavior(so->behavior) : 0; - u32 remoteBehaviorId = remoteBehaviorIds[so->id]; - if (localBehaviorId == 0 && remoteBehaviorId == 0) { continue; } - LOG_INFO("%03d: %04X %04X %s", so->id, localBehaviorId, remoteBehaviorId, (localBehaviorId == remoteBehaviorId) ? " " : "<<<"); + if (localBehaviorId != behaviorId) { + LOG_INFO("Sync Table MisMatch: %03d : %08X != %08X :: (%s != %s)", id, localBehaviorId, behaviorId, localBehaviorName, behaviorName); + return; } + } diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 400ab1ff2..fc49b498d 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -462,7 +462,7 @@ void network_update_objects(void) { #ifdef DEVELOPMENT static f32 lastDebugSync = 0; - if (clock_elapsed() - lastDebugSync >= 1) { + if (clock_elapsed() - lastDebugSync >= 5) { network_send_debug_sync(); lastDebugSync = clock_elapsed(); } diff --git a/src/pc/network/reservation_area.h b/src/pc/network/reservation_area.h index abc1d5d63..d40a09146 100644 --- a/src/pc/network/reservation_area.h +++ b/src/pc/network/reservation_area.h @@ -8,7 +8,7 @@ #include #define RESERVED_IDS_PER_PLAYER_COUNT 5 -#define RESERVED_IDS_SYNC_OBJECT_OFFSET 127 +#define RESERVED_IDS_SYNC_OBJECT_OFFSET 2048 struct NetworkPlayer; diff --git a/src/pc/network/sync_object.c b/src/pc/network/sync_object.c index 69e9790b0..e7a7034be 100644 --- a/src/pc/network/sync_object.c +++ b/src/pc/network/sync_object.c @@ -12,22 +12,76 @@ #include "pc/debuglog.h" #include "pc/utils/misc.h" -#define MAX_SYNC_OBJECTS 256 // note: increasing this requires code to be rewritten +#define STB_DS_IMPLEMENTATION 1 +#include "pc/utils/stb_ds.h" + +struct SyncObjectEntry { + u64 key; + struct SyncObject* value; +}; +struct SyncObjectEntry* sSoMap = NULL; + +struct SyncObjectForgetEntry { + struct SyncObject* so; + s32 forgetTimer; + struct SyncObjectForgetEntry* next; +}; +struct SyncObjectForgetEntry* sForgetList = NULL; -struct SyncObject sSyncObjects[MAX_SYNC_OBJECTS] = { 0 }; static u32 sNextSyncId = 0; -static u32 sIterateSyncId = 0; +static u32 sIterateIndex = 0; +static bool sFreeingAll = false; //////////// // system // //////////// +static bool sync_objects_forget_list_contains(struct SyncObject* so) { + struct SyncObjectForgetEntry* entry = sForgetList; + while (entry) { + struct SyncObjectForgetEntry* next = entry->next; + if (entry->so == so) { + return true; + } + entry = next; + } + return false; +} + +void sync_objects_update(void) { + struct SyncObjectForgetEntry* prev = NULL; + struct SyncObjectForgetEntry* entry = sForgetList; + while (entry) { + struct SyncObjectForgetEntry* next = entry->next; + + if (entry->forgetTimer-- <= 0) { + if (prev) { + prev->next = next; + } else { + sForgetList = next; + } + LOG_INFO("Freeing sync object... (%d)", entry->so->id); + free(entry->so); + free(entry); + + } else { + prev = entry; + } + + entry = next; + } +} + void sync_objects_clear(void) { sNextSyncId = 0; network_on_init_area(); - for (u32 i = 0; i < MAX_SYNC_OBJECTS; i++) { - sync_object_forget(i); + + sFreeingAll = true; + for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { + sync_object_forget(so->id); } + sFreeingAll = false; + hmfree(sSoMap); } void sync_object_forget(u32 syncId) { @@ -44,16 +98,38 @@ void sync_object_forget(u32 syncId) { area_remove_sync_ids_add(syncId2); } - if (so->on_forget != NULL) { + if (so->on_forget != NULL && so->o) { struct Object* lastObject = gCurrentObject; gCurrentObject = so->o; so->on_forget(); gCurrentObject = lastObject; } + so->o = NULL; so->behavior = NULL; so->owned = false; + + if (!sFreeingAll) { + hmdel(sSoMap, syncId); + } + + // add it to a list to free later + s32 forgetCount = 1; + struct SyncObjectForgetEntry* newEntry = calloc(1, sizeof(struct SyncObjectForgetEntry)); + newEntry->so = so; + newEntry->forgetTimer = 10; + if (sForgetList == NULL) { + sForgetList = newEntry; + } else { + struct SyncObjectForgetEntry* entry = sForgetList; + while (entry->next != NULL) { + entry = entry->next; + forgetCount++; + } + entry->next = newEntry; + } + LOG_INFO("Scheduling sync object to free... (%d)", so->id); } void sync_object_forget_last_reliable_packet(u32 syncId) { @@ -129,7 +205,11 @@ void sync_object_init_field(struct Object *o, void* field) { struct SyncObject* so = sync_object_get(o->oSyncID); if (!so) { return; } u32 index = so->extraFieldCount++; - if (so->extraFieldCount >= MAX_SYNC_OBJECT_FIELDS) { return; } + if (so->extraFieldCount >= MAX_SYNC_OBJECT_FIELDS) { + so->extraFieldCount = MAX_SYNC_OBJECT_FIELDS - 1; + LOG_ERROR("Sync Object %u tried to set too many extra fields!", o->oSyncID); + return; + } so->extraFields[index] = field; so->extraFieldsSize[index] = 32; } @@ -144,7 +224,11 @@ void sync_object_init_field_with_size(struct Object *o, void* field, u8 size) { struct SyncObject* so = sync_object_get(o->oSyncID); if (!so) { return; } u32 index = so->extraFieldCount++; - if (so->extraFieldCount >= MAX_SYNC_OBJECT_FIELDS) { return; } + if (so->extraFieldCount >= MAX_SYNC_OBJECT_FIELDS) { + so->extraFieldCount = MAX_SYNC_OBJECT_FIELDS - 1; + LOG_ERROR("Sync Object %u tried to set too many extra fields!", o->oSyncID); + return; + } so->extraFields[index] = field; so->extraFieldsSize[index] = size; } @@ -154,24 +238,23 @@ void sync_object_init_field_with_size(struct Object *o, void* field, u8 size) { ///////////// struct SyncObject* sync_object_get(u32 syncId) { - if (syncId >= MAX_SYNC_OBJECTS) { return NULL; } - return &sSyncObjects[syncId]; + return hmget(sSoMap, syncId); } struct SyncObject* sync_object_get_first(void) { - sIterateSyncId = 0; - return &sSyncObjects[sIterateSyncId]; -} - -struct SyncObject* sync_object_get_first_non_static(void) { - sIterateSyncId = RESERVED_IDS_SYNC_OBJECT_OFFSET; - return &sSyncObjects[sIterateSyncId]; + sIterateIndex = 0; + if (sSoMap && sIterateIndex < hmlen(sSoMap)) { + return sSoMap[sIterateIndex].value; + } + return NULL; } struct SyncObject* sync_object_get_next(void) { - sIterateSyncId++; - if (sIterateSyncId >= MAX_SYNC_OBJECTS) { return NULL; } - return &sSyncObjects[sIterateSyncId]; + sIterateIndex++; + if (sSoMap && sIterateIndex < hmlen(sSoMap)) { + return sSoMap[sIterateIndex].value; + } + return NULL; } struct Object* sync_object_get_object(u32 syncId) { @@ -277,49 +360,34 @@ bool sync_object_should_own(u32 syncId) { return true; } -static u32 sync_object_find_cached_id(struct Object* o) { - u32 behaviorId = get_id_from_behavior(o->behavior); - for (s32 i = 1; i < 256; i++) { - struct SyncObject* so = sync_object_get(i); - if (!so) { continue; } - if (so->o != NULL) { continue; } - u32 cachedBehaviorId = gCurrentArea->cachedBehaviors[i]; - if (cachedBehaviorId != behaviorId) { continue; } - - f32 dist = dist_between_object_and_point(o, gCurrentArea->cachedPositions[i][0], gCurrentArea->cachedPositions[i][1], gCurrentArea->cachedPositions[i][2]); - if (dist > 1) { continue; } - return i; +u32 sync_object_get_available_local_id() { + u32 startId = (gNetworkPlayers[0].globalIndex + 1) * RESERVED_IDS_SYNC_OBJECT_OFFSET; + u32 endId = startId + RESERVED_IDS_SYNC_OBJECT_OFFSET; + for (u32 id = startId; id < endId; id++) { + struct SyncObject* so = sync_object_get(id); + if (so) { continue; } + return id; } return 0; } bool sync_object_set_id(struct Object* o) { - // check for existing id - if (o->oSyncID != 0) { return true; } - - u32 syncId = 0; - if (!gNetworkAreaLoaded) { - syncId = sync_object_find_cached_id(o); - if (syncId == 0) { - // while loading, just fill in sync ids from 1 to MAX_SYNC_OBJECTS - for (s32 i = 1; i < MAX_SYNC_OBJECTS; i++) { + u32 syncId = o->oSyncID; + if (syncId == 0) { + if (!gNetworkAreaLoaded) { + // while loading, just fill in sync ids from 1 to RESERVED_IDS_SYNC_OBJECT_OFFSET + for (s32 i = 1; i < RESERVED_IDS_SYNC_OBJECT_OFFSET; i++) { sNextSyncId++; sNextSyncId = sNextSyncId % RESERVED_IDS_SYNC_OBJECT_OFFSET; struct SyncObject* so = sync_object_get(sNextSyncId); - if (!so || so->o != NULL) { continue; } + if (so && so->o != NULL) { continue; } syncId = sNextSyncId; break; } - // cache this object's id - gCurrentArea->cachedBehaviors[syncId] = get_id_from_behavior(o->behavior); - gCurrentArea->cachedPositions[syncId][0] = o->oPosX; - gCurrentArea->cachedPositions[syncId][1] = o->oPosY; - gCurrentArea->cachedPositions[syncId][2] = o->oPosZ; - //LOG_INFO("set cached sync id for %02X: %d", gCurrentArea->cachedBehaviors[syncId], syncId); + } else { + // no longer loading, require reserved id + syncId = sync_object_get_available_local_id(); } - } else { - // no longer loading, require reserved id - syncId = reservation_area_local_grab_id(); } if (syncId == 0) { @@ -328,7 +396,16 @@ bool sync_object_set_id(struct Object* o) { } struct SyncObject* so = sync_object_get(syncId); - if (!so || so->o != NULL) { + + if (!so) { + so = calloc(1, sizeof(struct SyncObject)); + so->id = syncId; + so->extendedModelId = 0xFFFF; + hmput(sSoMap, syncId, so); + LOG_INFO("Allocated sync object @ %u, size %ld", syncId, hmlen(sSoMap)); + } + + if (!so) { LOG_ERROR("failed to set sync id (o) for object w/behavior %d (set_sync_id) %u", get_id_from_behavior(o->behavior), gNetworkAreaLoaded); return false; } @@ -339,6 +416,5 @@ bool sync_object_set_id(struct Object* o) { LOG_INFO("set sync id for object w/behavior %d", get_id_from_behavior(o->behavior)); } - SOFT_ASSERT_RETURN(o->oSyncID < MAX_SYNC_OBJECTS, false); return true; } diff --git a/src/pc/network/sync_object.h b/src/pc/network/sync_object.h index c5469cee6..dfb52be0f 100644 --- a/src/pc/network/sync_object.h +++ b/src/pc/network/sync_object.h @@ -40,7 +40,7 @@ struct SyncObject { //////////// // system // //////////// - +void sync_objects_update(void); void sync_objects_clear(void); void sync_object_forget(u32 syncId); void sync_object_forget_last_reliable_packet(u32 syncId); @@ -54,7 +54,6 @@ void sync_object_init_field_with_size(struct Object *o, void* field, u8 size); struct SyncObject* sync_object_get(u32 syncId); struct SyncObject* sync_object_get_first(void); -struct SyncObject* sync_object_get_first_non_static(void); struct SyncObject* sync_object_get_next(void); struct Object* sync_object_get_object(u32 syncId); bool sync_object_is_initialized(u32 syncId);