From 012e97f41056de79dfadbdae4a8d149dcf49d093 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sun, 18 Jan 2026 19:50:07 -0600 Subject: [PATCH] feat(object): add GarbageCollect --- src/object/client/MessageHandlers.cpp | 10 +++++++++- src/object/client/ObjMgr.cpp | 6 +++++- src/object/client/ObjMgr.hpp | 2 ++ src/object/client/Util.cpp | 24 ++++++++++++++++++++++++ src/object/client/Util.hpp | 2 ++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/object/client/MessageHandlers.cpp b/src/object/client/MessageHandlers.cpp index cac7254..ab77288 100644 --- a/src/object/client/MessageHandlers.cpp +++ b/src/object/client/MessageHandlers.cpp @@ -384,6 +384,8 @@ int32_t ObjectUpdateHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataS uint32_t updateCount; msg->Get(updateCount); + // If first update type is out of range, handle it before continuing with normal processing + auto startPos = msg->Tell(); uint8_t firstUpdateType; @@ -398,6 +400,8 @@ int32_t ObjectUpdateHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataS msg->Seek(startPos); } + // Process all updates in two passes (creates, updates and disables objects as appropriate) + int32_t result = 0; if (ObjectUpdateFirstPass(msg, time, updateIdx, updateCount)) { @@ -405,7 +409,11 @@ int32_t ObjectUpdateHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataS result = ObjectUpdateSecondPass(msg, time, updateCount); } - // TODO + // Garbage collect objects disabled more than 2 minutes ago (catch all) + + for (int32_t typeID = ID_OBJECT; typeID < NUM_CLIENT_OBJECT_TYPES; typeID++) { + GarbageCollect(static_cast(typeID), 120000); + } return result; } diff --git a/src/object/client/ObjMgr.cpp b/src/object/client/ObjMgr.cpp index a159c4f..b0b582a 100644 --- a/src/object/client/ObjMgr.cpp +++ b/src/object/client/ObjMgr.cpp @@ -75,7 +75,7 @@ CGObject_C* ClntObjMgrAllocObject(OBJECT_TYPE_ID typeID, WOWGUID guid) { return static_cast(STORM_ALLOC(sizeof(CGPlayer_C) + CGPlayer::GetDataSize() + CGPlayer::GetDataSizeSaved())); } - // TODO GarbageCollect(typeID, 10000); + GarbageCollect(typeID, 10000); uint32_t memHandle; void* mem; @@ -91,6 +91,10 @@ CGObject_C* ClntObjMgrAllocObject(OBJECT_TYPE_ID typeID, WOWGUID guid) { return object; } +void ClntObjMgrFreeObject(CGObject_C* object) { + // TODO +} + WOWGUID ClntObjMgrGetActivePlayer() { if (!s_curMgr) { return 0; diff --git a/src/object/client/ObjMgr.hpp b/src/object/client/ObjMgr.hpp index 6d5fd09..f467d9d 100644 --- a/src/object/client/ObjMgr.hpp +++ b/src/object/client/ObjMgr.hpp @@ -10,6 +10,8 @@ CGObject_C* ClntObjMgrAllocObject(OBJECT_TYPE_ID typeID, WOWGUID guid); WOWGUID ClntObjMgrGetActivePlayer(); +void ClntObjMgrFreeObject(CGObject_C* object); + ClntObjMgr* ClntObjMgrGetCurrent(); uint32_t ClntObjMgrGetMapID(); diff --git a/src/object/client/Util.cpp b/src/object/client/Util.cpp index 574960c..6dd3e82 100644 --- a/src/object/client/Util.cpp +++ b/src/object/client/Util.cpp @@ -9,11 +9,35 @@ #include "object/client/CGPlayer_C.hpp" #include "object/client/CGUnit_C.hpp" #include "object/client/ObjMgr.hpp" +#include CGObject_C* FindActiveObject(WOWGUID guid) { return ClntObjMgrGetCurrent()->m_objects.Ptr(guid, CHashKeyGUID(guid)); } +/** + * Given an object type and collection age, free the object at the head of that type's FIFO queue + * if it was disabled longer ago than the collection age. Only frees at most one object per call. + */ +void GarbageCollect(OBJECT_TYPE_ID typeID, uint32_t collectAgeMs) { + auto object = ClntObjMgrGetCurrent()->m_lazyCleanupFifo[typeID - 1].Head(); + + if (!object) { + return; + } + + uint32_t disableAgeMs = OsGetAsyncTimeMsPrecise() - object->m_disableTimeMs; + + if (disableAgeMs < collectAgeMs) { + return; + } + + ClntObjMgrGetCurrent()->m_lazyCleanupObjects.Unlink(object); + object->m_link.Unlink(); + + ClntObjMgrFreeObject(object); +} + CGObject_C* GetUpdateObject(WOWGUID guid, int32_t* reenable) { *reenable = false; diff --git a/src/object/client/Util.hpp b/src/object/client/Util.hpp index e425f83..b39c6db 100644 --- a/src/object/client/Util.hpp +++ b/src/object/client/Util.hpp @@ -10,6 +10,8 @@ class CGObject_C; CGObject_C* FindActiveObject(WOWGUID guid); +void GarbageCollect(OBJECT_TYPE_ID typeID, uint32_t collectAgeMs); + CGObject_C* GetUpdateObject(WOWGUID guid, int32_t* reenable); int32_t HandleObjectOutOfRangePass1(CGObject_C* object, OUT_OF_RANGE_TYPE type);