diff --git a/src/object/client/MessageHandlers.cpp b/src/object/client/MessageHandlers.cpp index 9deef23..ad842bd 100644 --- a/src/object/client/MessageHandlers.cpp +++ b/src/object/client/MessageHandlers.cpp @@ -1,9 +1,297 @@ #include "object/client/MessageHandlers.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/Mirror.hpp" +#include "object/client/ObjMgr.hpp" +#include "util/GUID.hpp" #include "util/Unimplemented.hpp" #include "util/Zlib.hpp" #include #include #include +#include + +enum UPDATE_TYPE { + UPDATE_PARTIAL = 0, + UPDATE_MOVEMENT = 1, + UPDATE_FULL = 2, + UPDATE_3 = 3, + UPDATE_OUT_OF_RANGE = 4, + UPDATE_IN_RANGE = 5, +}; + +CGObject_C* GetUpdateObject(WOWGUID guid, int32_t* reenabled) { + WHOA_UNIMPLEMENTED(nullptr); +} + +void UpdateOutOfRangeObjects(CDataStore* msg) { + WHOA_UNIMPLEMENTED(); +} + +int32_t UpdateObject(CDataStore* msg) { + WHOA_UNIMPLEMENTED(0); +} + +void UpdateObjectMovement(CDataStore* msg) { + WHOA_UNIMPLEMENTED(); +} + +void SetupObjectStorage(OBJECT_TYPE_ID typeID, CGObject_C* object, WOWGUID guid) { + auto ptr = reinterpret_cast(object); + + switch (typeID) { + case ID_OBJECT: { + auto storage = reinterpret_cast(ptr + sizeof(CGObject_C)); + auto saved = storage + CGObject::TotalFields(); + + object->SetStorage(storage, saved); + memset(storage, 0, CGObject::GetDataSize()); + + break; + } + + case ID_ITEM: { + auto storage = reinterpret_cast(ptr + sizeof(CGItem_C)); + auto saved = storage + CGItem::TotalFields(); + + static_cast(object)->SetStorage(storage, saved); + memset(storage, 0, CGItem::GetDataSize()); + + break; + } + + case ID_CONTAINER: { + auto storage = reinterpret_cast(ptr + sizeof(CGContainer_C)); + auto saved = storage + CGContainer::TotalFields(); + + static_cast(object)->SetStorage(storage, saved); + memset(storage, 0, CGContainer::GetDataSize()); + + break; + } + + case ID_UNIT: { + auto storage = reinterpret_cast(ptr + sizeof(CGUnit_C)); + auto saved = storage + CGUnit::TotalFields(); + + static_cast(object)->SetStorage(storage, saved); + memset(storage, 0, CGUnit::GetDataSize()); + + break; + } + + case ID_PLAYER: { + // TODO something at ptr + 0x614 (within CGPlayer_C) + + if (guid == ClntObjMgrGetActivePlayer()) { + auto storage = reinterpret_cast(ptr + sizeof(CGPlayer_C)); + auto saved = storage + CGPlayer::TotalFields(); + + static_cast(object)->SetStorage(storage, saved); + memset(storage, 0, CGPlayer::GetDataSize()); + } else { + auto storage = reinterpret_cast(ptr + sizeof(CGPlayer_C)); + auto saved = storage + CGPlayer::TotalRemoteFields(); + + static_cast(object)->SetStorage(storage, saved); + memset(storage, 0, CGPlayer::GetRemoteDataSize()); + } + + break; + } + + case ID_GAMEOBJECT: { + auto storage = reinterpret_cast(ptr + sizeof(CGGameObject_C)); + auto saved = storage + CGGameObject::TotalFields(); + + static_cast(object)->SetStorage(storage, saved); + memset(storage, 0, CGGameObject::GetDataSize()); + + break; + } + + case ID_DYNAMICOBJECT: { + auto storage = reinterpret_cast(ptr + sizeof(CGDynamicObject_C)); + auto saved = storage + CGDynamicObject::TotalFields(); + + static_cast(object)->SetStorage(storage, saved); + memset(storage, 0, CGDynamicObject::GetDataSize()); + + break; + } + + case ID_CORPSE: { + auto storage = reinterpret_cast(ptr + sizeof(CGCorpse_C)); + auto saved = storage + CGCorpse::TotalFields(); + + static_cast(object)->SetStorage(storage, saved); + memset(storage, 0, CGCorpse::GetDataSize()); + + break; + } + } +} + +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; + } + } +} + +int32_t CreateObject(CDataStore* msg, uint32_t time) { + SmartGUID guid; + *msg >> guid; + + uint8_t _typeID; + msg->Get(_typeID); + auto typeID = static_cast(_typeID); + + int32_t reenabled; + auto existingObject = GetUpdateObject(guid, &reenabled); + + if (existingObject) { + // TODO + return 0; + } + + CClientObjCreate objCreate; + if (!objCreate.Get(msg)) { + return 0; + } + + if (objCreate.flags & 0x1) { + ClntObjMgrSetActivePlayer(guid); + } + + auto newObject = static_cast(ClntObjMgrAllocObject(typeID, guid)); + + SetupObjectStorage(typeID, newObject, guid); + + newObject->SetTypeID(typeID); + + if (!FillInPartialObjectData(newObject, guid, msg, true, false)) { + return 0; + } + + InitObject(newObject, time, objCreate); + + // TODO link to one of the ClntObjMgr lists + + return 1; +} + +void UpdateInRangeObjects(CDataStore* msg) { + WHOA_UNIMPLEMENTED(); +} + +int32_t ObjectUpdateFirstPass(CDataStore* msg, uint32_t time, uint32_t updateIdx, uint32_t updateCount) { + for (uint32_t i = updateIdx; i < updateCount; i++) { + uint8_t updateType; + msg->Get(updateType); + + switch (updateType) { + case UPDATE_PARTIAL: { + if (!UpdateObject(msg)) { + return 0; + } + + break; + } + + case UPDATE_MOVEMENT: { + // Read but ignored in first pass + SmartGUID guid; + *msg >> guid; + + UpdateObjectMovement(msg); + + break; + } + + case UPDATE_FULL: + case UPDATE_3: { + if (!CreateObject(msg, time)) { + return 0; + } + + break; + } + + case UPDATE_IN_RANGE: { + UpdateInRangeObjects(msg); + + break; + } + + default: { + STORM_APP_FATAL("Unknown client update packet type (%d)!", updateType); + } + } + } + + return 1; +} + +int32_t ObjectUpdateSecondPass(CDataStore* msg, uint32_t time, uint32_t updateCount) { + // TODO + return 0; +} int32_t ObjectCompressedUpdateHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg) { uint32_t origSize; @@ -60,7 +348,33 @@ int32_t ObjectCompressedUpdateHandler(void* param, NETMESSAGE msgId, uint32_t ti } int32_t ObjectUpdateHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg) { - WHOA_UNIMPLEMENTED(0); + uint32_t updateCount; + msg->Get(updateCount); + + auto startPos = msg->Tell(); + + uint8_t firstUpdateType; + msg->Get(firstUpdateType); + + uint32_t updateIdx = 0; + + if (firstUpdateType == UPDATE_OUT_OF_RANGE) { + UpdateOutOfRangeObjects(msg); + updateIdx = 1; + } else { + msg->Seek(startPos); + } + + int32_t result = 0; + + if (ObjectUpdateFirstPass(msg, time, updateIdx, updateCount)) { + msg->Seek(startPos); + result = ObjectUpdateSecondPass(msg, time, updateCount); + } + + // TODO + + return result; } int32_t OnObjectDestroy(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg) {