Rewrite syncID allocation and memory structure

This commit is contained in:
MysterD 2023-03-26 18:43:35 -07:00
parent 6c8b6387b4
commit 015a49dc1a
11 changed files with 172 additions and 108 deletions

View file

@ -229,8 +229,6 @@ void clear_areas(void) {
gAreaData[i].dialog[1] = 255; gAreaData[i].dialog[1] = 255;
gAreaData[i].musicParam = 0; gAreaData[i].musicParam = 0;
gAreaData[i].musicParam2 = 0; gAreaData[i].musicParam2 = 0;
memset(gAreaData[i].cachedBehaviors, 0, sizeof(u8) * 256);
memset(gAreaData[i].cachedPositions, 0, sizeof(Vec3f) * 256);
} }
} }

View file

@ -45,6 +45,7 @@ struct SpawnInfo
/*0x14*/ void *behaviorScript; /*0x14*/ void *behaviorScript;
/*0x18*/ struct GraphNode *unk18; /*0x18*/ struct GraphNode *unk18;
/*0x1C*/ struct SpawnInfo *next; /*0x1C*/ struct SpawnInfo *next;
/*0x20*/ u32 syncID;
}; };
struct UnusedArea28 struct UnusedArea28
@ -81,8 +82,6 @@ struct Area
/*0x34*/ u8 dialog[2]; // Level start dialog number (set by level script cmd 0x30) /*0x34*/ u8 dialog[2]; // Level start dialog number (set by level script cmd 0x30)
/*0x36*/ u16 musicParam; /*0x36*/ u16 musicParam;
/*0x38*/ u16 musicParam2; /*0x38*/ u16 musicParam2;
/*????*/ u8 cachedBehaviors[256];
/*????*/ Vec3f cachedPositions[256];
/*????*/ u32 localAreaTimer; /*????*/ u32 localAreaTimer;
/*????*/ u8 *macroObjectsAltered; /*????*/ u8 *macroObjectsAltered;
/*????*/ u8 numRedCoins; /*????*/ u8 numRedCoins;

View file

@ -81,8 +81,11 @@ static void debug_reload_lua(void) {
} }
static void debug_spawn_object(void) { static void debug_spawn_object(void) {
for (int i = 0; i < 1; i++) {
struct Object* box = spawn_object(gMarioStates[0].marioObj, MODEL_BREAKABLE_BOX_SMALL, bhvBreakableBoxSmall); struct Object* box = spawn_object(gMarioStates[0].marioObj, MODEL_BREAKABLE_BOX_SMALL, bhvBreakableBoxSmall);
if (box == NULL) { return; } 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)) { if (!sync_object_set_id(box)) {
box->activeFlags = ACTIVE_FLAG_DEACTIVATED; box->activeFlags = ACTIVE_FLAG_DEACTIVATED;
return; return;
@ -91,6 +94,7 @@ static void debug_spawn_object(void) {
struct Object* spawn_objects[] = { box }; struct Object* spawn_objects[] = { box };
u32 models[] = { MODEL_BREAKABLE_BOX_SMALL }; u32 models[] = { MODEL_BREAKABLE_BOX_SMALL };
network_send_spawn_objects(spawn_objects, models, 1); network_send_spawn_objects(spawn_objects, models, 1);
}
} }
void debug_keyboard_on_key_down(int scancode) { void debug_keyboard_on_key_down(int scancode) {

View file

@ -1,6 +1,5 @@
#include <stdio.h> #include <stdio.h>
#include "smlua.h" #include "smlua.h"
#define STB_DS_IMPLEMENTATION 1
#include "pc/utils/stb_ds.h" #include "pc/utils/stb_ds.h"
struct AllowList { struct AllowList {

View file

@ -441,6 +441,8 @@ void network_update(void) {
packet_ordered_update(); packet_ordered_update();
} }
sync_objects_update();
// update level/area request timers // update level/area request timers
/*struct NetworkPlayer* np = gNetworkPlayerLocal; /*struct NetworkPlayer* np = gNetworkPlayerLocal;
if (np != NULL && !np->currLevelSyncValid) { if (np != NULL && !np->currLevelSyncValid) {

View file

@ -95,9 +95,10 @@ void network_send_area(struct NetworkPlayer* toNp) {
network_send_to(toNp->localIndex, &p); network_send_to(toNp->localIndex, &p);
// send non-static objects // 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 == NULL || so->o == NULL || so->o->oSyncID != so->id) { continue; }
if (so->o->behavior == smlua_override_behavior(bhvRespawner)) { 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 }; struct Object* spawn_objects[] = { so->o };
// TODO: move find model to a utility file/function // TODO: move find model to a utility file/function

View file

@ -14,54 +14,40 @@ static void print_sync_object_table(void) {
} }
void network_send_debug_sync(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()) { for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) {
if (!so || !so->o) { continue; } if (!so || !so->o) { continue; }
u32 behaviorId = get_id_from_behavior((so->behavior == NULL) ? so->behavior : so->o->behavior); 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, &so->id, sizeof(u32));
packet_write(&p, &behaviorId, sizeof(u32)); packet_write(&p, &behaviorId, sizeof(u32));
}
network_send(&p); network_send(&p);
}
} }
void network_receive_debug_sync(struct Packet* p) { void network_receive_debug_sync(struct Packet* p) {
u16 objectCount = 0; u32 id;
u32 remoteBehaviorIds[1024] = { 0 };
packet_read(p, &objectCount, sizeof(u16));
for (s32 i = 0; i < objectCount; i++) {
u32 j;
u32 behaviorId; u32 behaviorId;
packet_read(p, &j, sizeof(u32));
packet_read(p, &id, sizeof(u32));
packet_read(p, &behaviorId, sizeof(u32)); packet_read(p, &behaviorId, sizeof(u32));
remoteBehaviorIds[j] = behaviorId;
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; u32 localBehaviorId = get_id_from_behavior((so->behavior == NULL) ? so->behavior : so->o->behavior);
for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { char* localBehaviorName = (char*)get_behavior_name_from_id(localBehaviorId);
u32 localBehaviorId = (so && so->o) ? get_id_from_behavior(so->behavior) : 0; if (!localBehaviorName) { localBehaviorName = "UNKNOWN"; }
u32 remoteBehaviorId = remoteBehaviorIds[so->id];
if (localBehaviorId != remoteBehaviorId) {
hasMismatch = true;
break;
}
}
if (!hasMismatch) { return; }
LOG_INFO(" "); if (localBehaviorId != behaviorId) {
LOG_INFO("Sync Object Table Mismatch"); LOG_INFO("Sync Table MisMatch: %03d : %08X != %08X :: (%s != %s)", id, localBehaviorId, behaviorId, localBehaviorName, behaviorName);
for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { return;
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) ? " " : "<<<");
} }
} }

View file

@ -462,7 +462,7 @@ void network_update_objects(void) {
#ifdef DEVELOPMENT #ifdef DEVELOPMENT
static f32 lastDebugSync = 0; static f32 lastDebugSync = 0;
if (clock_elapsed() - lastDebugSync >= 1) { if (clock_elapsed() - lastDebugSync >= 5) {
network_send_debug_sync(); network_send_debug_sync();
lastDebugSync = clock_elapsed(); lastDebugSync = clock_elapsed();
} }

View file

@ -8,7 +8,7 @@
#include <stdbool.h> #include <stdbool.h>
#define RESERVED_IDS_PER_PLAYER_COUNT 5 #define RESERVED_IDS_PER_PLAYER_COUNT 5
#define RESERVED_IDS_SYNC_OBJECT_OFFSET 127 #define RESERVED_IDS_SYNC_OBJECT_OFFSET 2048
struct NetworkPlayer; struct NetworkPlayer;

View file

@ -12,22 +12,76 @@
#include "pc/debuglog.h" #include "pc/debuglog.h"
#include "pc/utils/misc.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 sNextSyncId = 0;
static u32 sIterateSyncId = 0; static u32 sIterateIndex = 0;
static bool sFreeingAll = false;
//////////// ////////////
// system // // 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) { void sync_objects_clear(void) {
sNextSyncId = 0; sNextSyncId = 0;
network_on_init_area(); 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) { void sync_object_forget(u32 syncId) {
@ -44,16 +98,38 @@ void sync_object_forget(u32 syncId) {
area_remove_sync_ids_add(syncId2); area_remove_sync_ids_add(syncId2);
} }
if (so->on_forget != NULL) { if (so->on_forget != NULL && so->o) {
struct Object* lastObject = gCurrentObject; struct Object* lastObject = gCurrentObject;
gCurrentObject = so->o; gCurrentObject = so->o;
so->on_forget(); so->on_forget();
gCurrentObject = lastObject; gCurrentObject = lastObject;
} }
so->o = NULL; so->o = NULL;
so->behavior = NULL; so->behavior = NULL;
so->owned = false; 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) { 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); struct SyncObject* so = sync_object_get(o->oSyncID);
if (!so) { return; } if (!so) { return; }
u32 index = so->extraFieldCount++; 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->extraFields[index] = field;
so->extraFieldsSize[index] = 32; 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); struct SyncObject* so = sync_object_get(o->oSyncID);
if (!so) { return; } if (!so) { return; }
u32 index = so->extraFieldCount++; 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->extraFields[index] = field;
so->extraFieldsSize[index] = size; 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) { struct SyncObject* sync_object_get(u32 syncId) {
if (syncId >= MAX_SYNC_OBJECTS) { return NULL; } return hmget(sSoMap, syncId);
return &sSyncObjects[syncId];
} }
struct SyncObject* sync_object_get_first(void) { struct SyncObject* sync_object_get_first(void) {
sIterateSyncId = 0; sIterateIndex = 0;
return &sSyncObjects[sIterateSyncId]; if (sSoMap && sIterateIndex < hmlen(sSoMap)) {
} return sSoMap[sIterateIndex].value;
}
struct SyncObject* sync_object_get_first_non_static(void) { return NULL;
sIterateSyncId = RESERVED_IDS_SYNC_OBJECT_OFFSET;
return &sSyncObjects[sIterateSyncId];
} }
struct SyncObject* sync_object_get_next(void) { struct SyncObject* sync_object_get_next(void) {
sIterateSyncId++; sIterateIndex++;
if (sIterateSyncId >= MAX_SYNC_OBJECTS) { return NULL; } if (sSoMap && sIterateIndex < hmlen(sSoMap)) {
return &sSyncObjects[sIterateSyncId]; return sSoMap[sIterateIndex].value;
}
return NULL;
} }
struct Object* sync_object_get_object(u32 syncId) { struct Object* sync_object_get_object(u32 syncId) {
@ -277,49 +360,34 @@ bool sync_object_should_own(u32 syncId) {
return true; return true;
} }
static u32 sync_object_find_cached_id(struct Object* o) { u32 sync_object_get_available_local_id() {
u32 behaviorId = get_id_from_behavior(o->behavior); u32 startId = (gNetworkPlayers[0].globalIndex + 1) * RESERVED_IDS_SYNC_OBJECT_OFFSET;
for (s32 i = 1; i < 256; i++) { u32 endId = startId + RESERVED_IDS_SYNC_OBJECT_OFFSET;
struct SyncObject* so = sync_object_get(i); for (u32 id = startId; id < endId; id++) {
if (!so) { continue; } struct SyncObject* so = sync_object_get(id);
if (so->o != NULL) { continue; } if (so) { continue; }
u32 cachedBehaviorId = gCurrentArea->cachedBehaviors[i]; return id;
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;
} }
return 0; return 0;
} }
bool sync_object_set_id(struct Object* o) { bool sync_object_set_id(struct Object* o) {
// check for existing id u32 syncId = o->oSyncID;
if (o->oSyncID != 0) { return true; }
u32 syncId = 0;
if (!gNetworkAreaLoaded) {
syncId = sync_object_find_cached_id(o);
if (syncId == 0) { if (syncId == 0) {
// while loading, just fill in sync ids from 1 to MAX_SYNC_OBJECTS if (!gNetworkAreaLoaded) {
for (s32 i = 1; i < MAX_SYNC_OBJECTS; i++) { // 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 = sNextSyncId % RESERVED_IDS_SYNC_OBJECT_OFFSET; sNextSyncId = sNextSyncId % RESERVED_IDS_SYNC_OBJECT_OFFSET;
struct SyncObject* so = sync_object_get(sNextSyncId); struct SyncObject* so = sync_object_get(sNextSyncId);
if (!so || so->o != NULL) { continue; } if (so && so->o != NULL) { continue; }
syncId = sNextSyncId; syncId = sNextSyncId;
break; 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 { } else {
// no longer loading, require reserved id // no longer loading, require reserved id
syncId = reservation_area_local_grab_id(); syncId = sync_object_get_available_local_id();
}
} }
if (syncId == 0) { if (syncId == 0) {
@ -328,7 +396,16 @@ bool sync_object_set_id(struct Object* o) {
} }
struct SyncObject* so = sync_object_get(syncId); 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); 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; 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)); 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; return true;
} }

View file

@ -40,7 +40,7 @@ struct SyncObject {
//////////// ////////////
// system // // system //
//////////// ////////////
void sync_objects_update(void);
void sync_objects_clear(void); void sync_objects_clear(void);
void sync_object_forget(u32 syncId); void sync_object_forget(u32 syncId);
void sync_object_forget_last_reliable_packet(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(u32 syncId);
struct SyncObject* sync_object_get_first(void); struct SyncObject* sync_object_get_first(void);
struct SyncObject* sync_object_get_first_non_static(void);
struct SyncObject* sync_object_get_next(void); struct SyncObject* sync_object_get_next(void);
struct Object* sync_object_get_object(u32 syncId); struct Object* sync_object_get_object(u32 syncId);
bool sync_object_is_initialized(u32 syncId); bool sync_object_is_initialized(u32 syncId);