whoa/src/object/client/Util.cpp
2026-01-18 19:50:07 -06:00

167 lines
4.4 KiB
C++

#include "object/client/Util.hpp"
#include "object/client/CClientObjCreate.hpp"
#include "object/client/CGContainer_C.hpp"
#include "object/client/CGCorpse_C.hpp"
#include "object/client/CGDynamicObject_C.hpp"
#include "object/client/CGGameObject_C.hpp"
#include "object/client/CGItem_C.hpp"
#include "object/client/CGObject_C.hpp"
#include "object/client/CGPlayer_C.hpp"
#include "object/client/CGUnit_C.hpp"
#include "object/client/ObjMgr.hpp"
#include <common/Time.hpp>
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;
// Active object
auto activeObject = FindActiveObject(guid);
if (activeObject) {
activeObject->SetDisablePending(false);
return activeObject;
}
// Disabled object
auto disabledObject = ClntObjMgrGetCurrent()->m_lazyCleanupObjects.Ptr(guid, CHashKeyGUID(guid));
if (disabledObject) {
ClntObjMgrGetCurrent()->m_lazyCleanupObjects.Unlink(disabledObject);
disabledObject->m_link.Unlink();
ClntObjMgrGetCurrent()->m_objects.Insert(disabledObject, guid, CHashKeyGUID(guid));
// These link checks are guaranteed to pass because of the unlink above (both lists share
// the same link). This check is either from an inlined function or is cruft left behind
// after a refactor.
if (
!ClntObjMgrGetCurrent()->m_visibleObjects.IsLinked(disabledObject)
&& !ClntObjMgrGetCurrent()->m_reenabledObjects.IsLinked(disabledObject)
) {
*reenable = true;
ClntObjMgrGetCurrent()->m_reenabledObjects.LinkToTail(disabledObject);
}
return disabledObject;
}
// Object not found
return nullptr;
}
int32_t HandleObjectOutOfRangePass1(CGObject_C* object, OUT_OF_RANGE_TYPE type) {
// TODO arena unit out of range handling
object->HandleOutOfRange(type);
if (object->IsObjectLocked()) {
object->SetDisablePending(true);
return false;
}
object->SetDisablePending(false);
object->Disable();
return true;
}
void HandleObjectOutOfRangePass2(CGObject_C* object) {
// TODO ClearObjectMirrorHandlers(object);
ClntObjMgrGetCurrent()->m_objects.Unlink(object);
if (ClntObjMgrGetCurrent()->m_visibleObjects.IsLinked(object)) {
ClntObjMgrGetCurrent()->m_visibleObjects.UnlinkNode(object);
}
ClntObjMgrGetCurrent()->m_lazyCleanupObjects.Insert(object, object->m_hashval, CHashKeyGUID(object->m_key));
ClntObjMgrGetCurrent()->m_lazyCleanupFifo[object->m_typeID - 1].LinkToTail(object);
}
void InitObject(CGObject_C* object, uint32_t time, CClientObjCreate& objCreate) {
switch (object->m_typeID) {
case ID_ITEM: {
new (object) CGItem_C(time, objCreate);
break;
}
case ID_CONTAINER: {
new (object) CGContainer_C(time, objCreate);
break;
}
case ID_UNIT: {
new (object) CGUnit_C(time, objCreate);
object->AddWorldObject();
break;
}
case ID_PLAYER: {
new (object) CGPlayer_C(time, objCreate);
object->AddWorldObject();
break;
}
case ID_GAMEOBJECT: {
new (object) CGGameObject_C(time, objCreate);
object->AddWorldObject();
break;
}
case ID_DYNAMICOBJECT: {
new (object) CGDynamicObject_C(time, objCreate);
object->AddWorldObject();
break;
}
case ID_CORPSE: {
new (object) CGCorpse_C(time, objCreate);
object->AddWorldObject();
break;
}
default: {
break;
}
}
}