diff --git a/LibCmo/CK2/CKContext.cpp b/LibCmo/CK2/CKContext.cpp index af76e64..0a28495 100644 --- a/LibCmo/CK2/CKContext.cpp +++ b/LibCmo/CK2/CKContext.cpp @@ -36,7 +36,7 @@ namespace LibCmo::CK2 { #pragma region Objects Management - ObjImpls::CKObject* CKContext::CreateCKObject(CK_CLASSID cls, CKSTRING name, + ObjImpls::CKObject* CKContext::CreateObject(CK_CLASSID cls, CKSTRING name, CK_OBJECTCREATION_OPTIONS options, CK_CREATIONMODE* res) { // todo: Process paramter options and res @@ -66,13 +66,13 @@ namespace LibCmo::CK2 { return obj; } - ObjImpls::CKObject* CKContext::GetCKObject(CK_ID id) { + ObjImpls::CKObject* CKContext::GetObject(CK_ID id) { if (id >= m_ObjectsList.size()) return nullptr; return m_ObjectsList[id]; } /** - * @brief The real CKObject destroy worker shared by CKContext::DestroyCKObject and CKContext::~CKContext + * @brief The real CKObject destroy worker shared by CKContext::DestroyObject and CKContext::~CKContext * @param[in] ctx The CKContext * @param[in] obj The CKObject need to be free. */ @@ -88,7 +88,7 @@ namespace LibCmo::CK2 { // free it and return its value desc->ReleaseFct(ctx, obj); } - void CKContext::DestroyCKObject(CK_ID id) { + void CKContext::DestroyObject(CK_ID id) { if (id >= m_ObjectsList.size()) return; // get object and free it diff --git a/LibCmo/CK2/CKContext.hpp b/LibCmo/CK2/CKContext.hpp index 4abaacb..4fa3c6e 100644 --- a/LibCmo/CK2/CKContext.hpp +++ b/LibCmo/CK2/CKContext.hpp @@ -37,11 +37,11 @@ namespace LibCmo::CK2 { * @remark CKObjects must be destroy with the DestroyObject method. * @see CKObject, DestroyObject */ - ObjImpls::CKObject* CreateCKObject(CK_CLASSID cls, CKSTRING name, + ObjImpls::CKObject* CreateObject(CK_CLASSID cls, CKSTRING name, CK_OBJECTCREATION_OPTIONS options = CK_OBJECTCREATION_OPTIONS::CK_OBJECTCREATION_NONAMECHECK, CK_CREATIONMODE* res = nullptr); - ObjImpls::CKObject* GetCKObject(CK_ID id); - void DestroyCKObject(CK_ID id); + ObjImpls::CKObject* GetObject(CK_ID id); + void DestroyObject(CK_ID id); CKDWORD AllocateGroupGlobalIndex(); CKDWORD AllocateSceneGlobalIndex(); diff --git a/LibCmo/CK2/CKFileReader.cpp b/LibCmo/CK2/CKFileReader.cpp index 33e89fd..71ac9b0 100644 --- a/LibCmo/CK2/CKFileReader.cpp +++ b/LibCmo/CK2/CKFileReader.cpp @@ -348,7 +348,7 @@ namespace LibCmo::CK2 { if (obj.Data == nullptr) continue; // create object and assign created obj ckid - obj.ObjPtr = m_Ctx->CreateCKObject(obj.ObjectCid, obj.Name.c_str()); + obj.ObjPtr = m_Ctx->CreateObject(obj.ObjectCid, obj.Name.c_str()); if (obj.ObjPtr == nullptr) { obj.CreatedObjectId = 0u; } else { @@ -378,7 +378,7 @@ namespace LibCmo::CK2 { obj.Data = nullptr; } else { // if failed, delete it - m_Ctx->DestroyCKObject(obj.ObjectId); + m_Ctx->DestroyObject(obj.ObjectId); obj.ObjPtr = nullptr; obj.CreatedObjectId = 0u; } diff --git a/LibCmo/CK2/CKStateChunk.cpp b/LibCmo/CK2/CKStateChunk.cpp index 887b00a..55c992f 100644 --- a/LibCmo/CK2/CKStateChunk.cpp +++ b/LibCmo/CK2/CKStateChunk.cpp @@ -111,23 +111,21 @@ namespace LibCmo::CK2 { #pragma region Misc Funcs const ChunkProfile CKStateChunk::GetStateChunkProfile() { - ChunkProfile profile; + return ChunkProfile { + .m_ClassId = this->m_ClassId, + .m_DataDwSize = this->m_DataDwSize, + .m_pData = this->m_pData, - profile.m_ClassId = this->m_ClassId; - profile.m_DataDwSize = this->m_DataDwSize; - profile.m_pData = this->m_pData; + .m_DataVersion = this->m_DataVersion, + .m_ChunkVersion = this->m_ChunkVersion, - profile.m_DataVersion = this->m_DataVersion; - profile.m_ChunkVersion = this->m_ChunkVersion; + .m_ObjectListSize = this->m_ObjectList.size(), + .m_ChunkListSize = this->m_ChunkList.size(), + .m_ManagerListSize = this->m_ManagerList.size(), - profile.m_ObjectListSize = this->m_ObjectList.size(); - profile.m_ChunkListSize = this->m_ChunkList.size(); - profile.m_ManagerListSize = this->m_ManagerList.size(); - - profile.m_BindFile = this->m_BindFile; - profile.m_BindContext = this->m_BindContext; - - return profile; + .m_BindFile = this->m_BindFile, + .m_BindContext = this->m_BindContext, + }; } void CKStateChunk::Clear(void) { @@ -773,7 +771,7 @@ namespace LibCmo::CK2 { /* ========== Sequence Functions ==========*/ - bool CKStateChunk::ReadObjectIDSequence(std::vector* ls) { + bool CKStateChunk::ReadObjectIDSequence(XContainer::XArray* ls) { if (ls == nullptr) return false; ls->clear(); @@ -793,7 +791,7 @@ namespace LibCmo::CK2 { return true; } - bool CKStateChunk::ReadManagerIntSequence(CKGUID* guid, std::vector* ls) { + bool CKStateChunk::ReadManagerIntSequence(CKGUID* guid, XContainer::XArray* ls) { if (guid == nullptr || ls == nullptr) return false; // read count @@ -815,7 +813,7 @@ namespace LibCmo::CK2 { return true; } - bool CKStateChunk::ReadSubChunkSequence(std::vector* ls) { + bool CKStateChunk::ReadSubChunkSequence(XContainer::XArray* ls) { if (ls == nullptr) return false; // clear first @@ -848,17 +846,18 @@ namespace LibCmo::CK2 { return true; } - bool CKStateChunk::ReadObjectArray(std::vector* ls) { + bool CKStateChunk::ReadXObjectArray(XContainer::XObjectArray* ls) { if (ls == nullptr) return false; ls->clear(); // read count CKDWORD count; if (!this->ReadStruct(count)) return false; - if (!count) return true; // 0 size array + if (count == 0) return true; // 0 size array // old file size correction - if (this->m_ChunkVersion < CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) { + bool old_file = this->m_ChunkVersion < CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1; + if (old_file) { // skip 4. but I don't know why!!! this->Skip(4); if (!this->ReadStruct(count)) return false; @@ -874,21 +873,36 @@ namespace LibCmo::CK2 { return false; } - // remap id - if (this->m_BindFile != nullptr) { - if (cache < 0) { - id = 0u; - } else { - id = this->m_BindFile->GetFileObjectByIndex(cache)->CreatedObjectId; - } - } else { + // in old file or no bind file, the read data directly is CK_ID. + // in new file or has bind file, the read data is the index in FileObjects + if (old_file || this->m_BindFile == nullptr) { id = static_cast(cache); + } else { + if (cache < 0) id = 0; + else id = this->m_BindFile->GetFileObjectByIndex(cache)->CreatedObjectId; } } return true; } + bool CKStateChunk::ReadXObjectPointerArray(XContainer::XObjectPointerArray* ls) { + if (ls == nullptr) return false; + + // very very similar to ReadXObjectArray + // we execute it first. + XContainer::XObjectArray idarr; + if (!ReadXObjectArray(idarr)) return false; + + // then convert it to pointer list + ls->resize(idarr.size()); + for (size_t i = 0; i < idarr.size(); ++i) { + (*ls)[i] = m_BindContext->GetObject(idarr[i]); + } + + return true; + } + #pragma endregion diff --git a/LibCmo/CK2/CKStateChunk.hpp b/LibCmo/CK2/CKStateChunk.hpp index 1dedf9e..08eae81 100644 --- a/LibCmo/CK2/CKStateChunk.hpp +++ b/LibCmo/CK2/CKStateChunk.hpp @@ -119,14 +119,14 @@ namespace LibCmo::CK2 { /* ========== Basic Data Read Functions ==========*/ private: - /// - /// The base read function for all data. - /// This function will check all read requirements. - /// If you have use this function or functions calling this function. You do not need check any reading requirements anymore - /// - /// the pointer to data. must be allocated first. - /// the size of data in byte. - /// + /** + * @brief The base read function for all data. + * This function will check all read requirements. + * If you have use this function or functions calling this function. You do not need check any reading requirements anymore. + * @param data_ptr[out] the pointer to data. must be allocated first. + * @param size_in_byte[in] the size of data in byte. + * @return True if success. + */ bool ReadByteData(void* data_ptr, CKDWORD size_in_byte); public: /// @@ -228,8 +228,8 @@ namespace LibCmo::CK2 { /// /// /// - bool ReadObjectIDSequence(std::vector* ls); - inline bool ReadObjectIDSequence(std::vector& ls) { + bool ReadObjectIDSequence(XContainer::XArray* ls); + inline bool ReadObjectIDSequence(XContainer::XArray& ls) { return ReadObjectIDSequence(&ls); } @@ -240,8 +240,8 @@ namespace LibCmo::CK2 { /// /// /// - bool ReadManagerIntSequence(CKGUID* guid, std::vector* ls); - inline bool ReadManagerIntSequence(CKGUID& guid, std::vector& ls) { + bool ReadManagerIntSequence(CKGUID* guid, XContainer::XArray* ls); + inline bool ReadManagerIntSequence(CKGUID& guid, XContainer::XArray& ls) { return ReadManagerIntSequence(&guid, &ls); } @@ -252,20 +252,31 @@ namespace LibCmo::CK2 { /// /// /// - bool ReadSubChunkSequence(std::vector* ls); - inline bool ReadSubChunkSequence(std::vector& ls) { + bool ReadSubChunkSequence(XContainer::XArray* ls); + inline bool ReadSubChunkSequence(XContainer::XArray& ls) { return ReadSubChunkSequence(&ls); } - /// - /// Read Object Array (actually still is CK_ID) - /// ReadXObjectArray() and ReadObjectArray() redirect to this. - /// - /// - /// - bool ReadObjectArray(std::vector* ls); - inline bool ReadObjectArray(std::vector& ls) { - return ReadObjectArray(&ls); + /** + * @brief Read Object Array (actually still is CK_ID) + * @remark ReadObjectArray() and XObjectArray::Load redirect to this. + * @param ls The list + * @return True if success. + */ + bool ReadXObjectArray(XContainer::XObjectArray* ls); + inline bool ReadXObjectArray(XContainer::XObjectArray& ls) { + return ReadXObjectArray(&ls); + } + + /** + * @brief Read Object Array (actually is CKObject*) + * @remark ReadXObjectArray() and XObjectPointerArray::Load redirect to this. + * @param ls The list + * @return True if success + */ + bool ReadXObjectPointerArray(XContainer::XObjectPointerArray* ls); + inline bool ReadXObjectPointerArray(XContainer::XObjectPointerArray& ls) { + return ReadXObjectPointerArray(&ls); } //int ReadInt(); diff --git a/LibCmo/CK2/ObjImpls/CKBeObject.cpp b/LibCmo/CK2/ObjImpls/CKBeObject.cpp index 6a664b6..86d718e 100644 --- a/LibCmo/CK2/ObjImpls/CKBeObject.cpp +++ b/LibCmo/CK2/ObjImpls/CKBeObject.cpp @@ -1,6 +1,7 @@ #include "CKSceneObject.hpp" #include "../CKStateChunk.hpp" #include "CKBeObject.hpp" +#include "CKGroup.hpp" namespace LibCmo::CK2::ObjImpls { @@ -19,7 +20,10 @@ namespace LibCmo::CK2::ObjImpls { } bool CKBeObject::IsInGroup(CKGroup* group) { - return false; + if (group == nullptr) return false; + CKDWORD idx = group->CKBeObject_GetGroupIndex(); + if (idx >= m_Groups.size()) return false; + return m_Groups[idx]; } void CKBeObject::CKGroup_SetGroups(CKDWORD pos, bool val) { diff --git a/LibCmo/CK2/ObjImpls/CKGroup.cpp b/LibCmo/CK2/ObjImpls/CKGroup.cpp index b5920ab..aa48192 100644 --- a/LibCmo/CK2/ObjImpls/CKGroup.cpp +++ b/LibCmo/CK2/ObjImpls/CKGroup.cpp @@ -25,10 +25,35 @@ namespace LibCmo::CK2::ObjImpls { bool suc = CKBeObject::Load(chunk, file); if (!suc) return false; + // cleat self + this->Clear(); + + // get grouped objects + if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_GROUP::CK_STATESAVE_GROUPALL)) { + XContainer::XObjectPointerArray ptrs; + chunk->ReadXObjectPointerArray(ptrs); + + // filter pointer and check them type + for (auto& ptr : ptrs) { + // skip bad one + if (ptr == nullptr || ptr == this + || !CKIsChildClassOf(ptr->GetClassID(), CK_CLASSID::CKCID_BEOBJECT)) { + continue; + } + CKBeObject* beobj = static_cast(ptr); + if (beobj->IsInGroup(this)) continue; + + // add good one + beobj->CKGroup_SetGroups(m_GroupIndex, true); + m_ObjectArray.emplace_back(beobj); + } + + } + return true; } - CKDWORD CKGroup::GetGroupIndex() { + CKDWORD CKGroup::CKBeObject_GetGroupIndex() { return m_GroupIndex; } diff --git a/LibCmo/CK2/ObjImpls/CKGroup.hpp b/LibCmo/CK2/ObjImpls/CKGroup.hpp index 7a3531a..e9af684 100644 --- a/LibCmo/CK2/ObjImpls/CKGroup.hpp +++ b/LibCmo/CK2/ObjImpls/CKGroup.hpp @@ -19,7 +19,7 @@ namespace LibCmo::CK2::ObjImpls { virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override; //virtual void PostLoad() override; - CKDWORD GetGroupIndex(); + CKDWORD CKBeObject_GetGroupIndex(); // ===== Insert ===== CKERROR AddObject(CKBeObject *o);