mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-10-18 19:22:41 +00:00
Rewrite syncID allocation and memory structure
This commit is contained in:
parent
6c8b6387b4
commit
015a49dc1a
11 changed files with 172 additions and 108 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -81,8 +81,11 @@ static void debug_reload_lua(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);
|
||||
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;
|
||||
|
@ -92,6 +95,7 @@ static void debug_spawn_object(void) {
|
|||
u32 models[] = { MODEL_BREAKABLE_BOX_SMALL };
|
||||
network_send_spawn_objects(spawn_objects, models, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void debug_keyboard_on_key_down(int scancode) {
|
||||
if (gNetworkSystem == &gNetworkSystemSocket) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <stdio.h>
|
||||
#include "smlua.h"
|
||||
#define STB_DS_IMPLEMENTATION 1
|
||||
#include "pc/utils/stb_ds.h"
|
||||
|
||||
struct AllowList {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
void network_receive_debug_sync(struct Packet* p) {
|
||||
u16 objectCount = 0;
|
||||
u32 remoteBehaviorIds[1024] = { 0 };
|
||||
|
||||
packet_read(p, &objectCount, sizeof(u16));
|
||||
for (s32 i = 0; i < objectCount; i++) {
|
||||
u32 j;
|
||||
u32 id;
|
||||
u32 behaviorId;
|
||||
packet_read(p, &j, sizeof(u32));
|
||||
|
||||
packet_read(p, &id, 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;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#define RESERVED_IDS_PER_PLAYER_COUNT 5
|
||||
#define RESERVED_IDS_SYNC_OBJECT_OFFSET 127
|
||||
#define RESERVED_IDS_SYNC_OBJECT_OFFSET 2048
|
||||
|
||||
struct NetworkPlayer;
|
||||
|
||||
|
|
|
@ -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];
|
||||
sIterateIndex = 0;
|
||||
if (sSoMap && sIterateIndex < hmlen(sSoMap)) {
|
||||
return sSoMap[sIterateIndex].value;
|
||||
}
|
||||
|
||||
struct SyncObject* sync_object_get_first_non_static(void) {
|
||||
sIterateSyncId = RESERVED_IDS_SYNC_OBJECT_OFFSET;
|
||||
return &sSyncObjects[sIterateSyncId];
|
||||
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);
|
||||
u32 syncId = o->oSyncID;
|
||||
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++) {
|
||||
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 = reservation_area_local_grab_id();
|
||||
syncId = sync_object_get_available_local_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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue