basically finish register. still have bug
This commit is contained in:
parent
230b18c0ba
commit
c6608dec57
@ -162,7 +162,7 @@ namespace LibCmo::CK2 {
|
||||
for (CKDWORD i = 0; i < slotcount; ++i) {
|
||||
CreateImage(width, height, i);
|
||||
if (ReadSpecificFormatBitmap(chunk, GetImageDesc(i))) {
|
||||
hasReadSlot[i] = true;
|
||||
XContainer::NSXBitArray::Set(hasReadSlot, i);
|
||||
} else {
|
||||
ReleaseImage(i);
|
||||
}
|
||||
@ -183,7 +183,7 @@ namespace LibCmo::CK2 {
|
||||
for (CKDWORD i = 0; i < slotcount; ++i) {
|
||||
VxMath::VxImageDescEx rawcache;
|
||||
if (ReadRawBitmap(chunk, &rawcache)) {
|
||||
hasReadSlot[i] = true;
|
||||
XContainer::NSXBitArray::Set(hasReadSlot, i);
|
||||
|
||||
// do upside down blit
|
||||
CreateImage(rawcache.GetWidth(), rawcache.GetHeight(), i);
|
||||
@ -202,7 +202,7 @@ namespace LibCmo::CK2 {
|
||||
// MARK: a rough implement because we do not support this identifier
|
||||
for (CKDWORD i = 0; i < slotcount; ++i) {
|
||||
if (ReadOldRawBitmap(chunk, GetImageDesc(i))) {
|
||||
hasReadSlot[i] = true;
|
||||
XContainer::NSXBitArray::Set(hasReadSlot, i);
|
||||
} else {
|
||||
ReleaseImage(i);
|
||||
}
|
||||
@ -224,7 +224,7 @@ namespace LibCmo::CK2 {
|
||||
chunk->ReadString(filename);
|
||||
if (filename.empty()) continue;
|
||||
|
||||
bool isNotLoaded = (i >= hasReadSlot.size()) || (!hasReadSlot[i]);
|
||||
bool isNotLoaded = (i >= hasReadSlot.size()) || (!XContainer::NSXBitArray::IsSet(hasReadSlot, i));
|
||||
if (isNotLoaded) {
|
||||
// if this image is not loaded.
|
||||
// try resolve its file name and load it.
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "CKGlobals.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
|
||||
#include "ObjImpls/CKObject.hpp"
|
||||
#include "ObjImpls/CKSceneObject.hpp"
|
||||
@ -110,6 +111,20 @@ namespace LibCmo::CK2 {
|
||||
#pragma region CKClass Registration
|
||||
|
||||
static XContainer::XArray<CKClassDesc> g_CKClassInfo;
|
||||
|
||||
static bool GetClassIdIndex(CK_CLASSID cid, size_t& intcid) {
|
||||
intcid = static_cast<size_t>(cid);
|
||||
if (intcid >= g_CKClassInfo.size()) return false;
|
||||
if (!g_CKClassInfo[intcid].IsValid) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CKClassNeedNotificationFrom(CK_CLASSID listener, CK_CLASSID listenTo) {
|
||||
size_t idxListener, idxListenTo;
|
||||
if (!GetClassIdIndex(listener, idxListener) || !GetClassIdIndex(listenTo, idxListenTo)) return;
|
||||
|
||||
XContainer::NSXBitArray::Set(g_CKClassInfo[idxListener].ToBeNotify, static_cast<CKDWORD>(idxListenTo));
|
||||
}
|
||||
|
||||
CK_CLASSID CKClassGetNewIdentifier() {
|
||||
size_t classsize = g_CKClassInfo.size();
|
||||
@ -120,64 +135,8 @@ namespace LibCmo::CK2 {
|
||||
}
|
||||
}
|
||||
|
||||
static void ComputeParentsTable(CKClassDesc& desc) {
|
||||
// if it has done, do not process it again.
|
||||
if (desc.Done) return;
|
||||
|
||||
// find direct parent
|
||||
CKClassDesc& parent = g_CKClassInfo[static_cast<size_t>(desc.Parent)];
|
||||
if (!parent.IsValid) LIBPANIC("No such CK_CLASSID.");
|
||||
|
||||
// if it is not self inheritance, call recursively
|
||||
if (desc.Self != desc.Parent) {
|
||||
ComputeParentsTable(parent);
|
||||
}
|
||||
|
||||
// copy parent's parents
|
||||
desc.Parents = parent.Parents;
|
||||
// and set self as its parent
|
||||
desc.Parents[static_cast<size_t>(desc.Self)] = true;
|
||||
|
||||
// set derivation level
|
||||
desc.DerivationLevel = parent.DerivationLevel + 1;
|
||||
|
||||
// set done
|
||||
desc.Done = true;
|
||||
}
|
||||
static void CKBuildClassHierarchyTable() {
|
||||
// set Done to false and resize all XBitArray
|
||||
size_t classCount = g_CKClassInfo.size();
|
||||
for (auto& item : g_CKClassInfo) {
|
||||
if (!item.IsValid) continue;
|
||||
|
||||
item.Done = false;
|
||||
item.Parents.resize(classCount, false);
|
||||
item.Children.resize(classCount, false);
|
||||
}
|
||||
// compute parents
|
||||
for (auto& item : g_CKClassInfo) {
|
||||
if (!item.IsValid) continue;
|
||||
|
||||
ComputeParentsTable(item);
|
||||
}
|
||||
// compute children by parents table
|
||||
// iterate CKClassDesc::Parents and register it self to gotten parents
|
||||
for (auto& item : g_CKClassInfo) {
|
||||
if (!item.IsValid) continue;
|
||||
|
||||
for (size_t idx = 0; idx < classCount; ++idx) {
|
||||
if (!g_CKClassInfo[idx].IsValid) continue;
|
||||
|
||||
// if this idx is its parent,
|
||||
// add self to parent.
|
||||
if (item.Parents[idx]) {
|
||||
g_CKClassInfo[idx].Children[static_cast<size_t>(item.Self)] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void CKClassRegister(CK_CLASSID cid, CK_CLASSID parentCid,
|
||||
CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct) {
|
||||
CKClassRegisterFct regFct, CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct) {
|
||||
|
||||
// resize class desc array
|
||||
size_t intcid = static_cast<size_t>(cid);
|
||||
@ -190,6 +149,7 @@ namespace LibCmo::CK2 {
|
||||
desc.IsValid = true;
|
||||
desc.Self = cid;
|
||||
desc.Parent = parentCid;
|
||||
desc.RegisterFct = regFct;
|
||||
desc.CreationFct = createFct;
|
||||
desc.ReleaseFct = relFct;
|
||||
desc.NameFct = nameFct;
|
||||
@ -200,13 +160,6 @@ namespace LibCmo::CK2 {
|
||||
|
||||
#pragma region Class Hierarchy Management
|
||||
|
||||
static bool GetClassIdIndex(CK_CLASSID cid, size_t& intcid) {
|
||||
intcid = static_cast<size_t>(cid);
|
||||
if (intcid >= g_CKClassInfo.size()) return false;
|
||||
if (!g_CKClassInfo[intcid].IsValid) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
CKDWORD CKGetClassCount() {
|
||||
return static_cast<CKDWORD>(g_CKClassInfo.size());
|
||||
}
|
||||
@ -248,18 +201,172 @@ namespace LibCmo::CK2 {
|
||||
return cid1;
|
||||
}
|
||||
|
||||
bool CKIsNeedNotify(CK_CLASSID listener, CK_CLASSID deletedObjCid) {
|
||||
const CKClassDesc* desc = CKGetClassDesc(listener);
|
||||
if (desc == nullptr) return false;
|
||||
return XContainer::NSXBitArray::IsSet(desc->CommonToBeNotify, static_cast<CKDWORD>(deletedObjCid));
|
||||
}
|
||||
|
||||
XContainer::XBitArray CKGetAllNotifyClassID(const XContainer::XBitArray& delObjCids) {
|
||||
XContainer::XBitArray result;
|
||||
|
||||
for (size_t i = 0; i < delObjCids.size(); ++i) {
|
||||
if (!XContainer::NSXBitArray::IsSet(delObjCids, static_cast<CKDWORD>(i))) continue;
|
||||
|
||||
const CKClassDesc* desc = CKGetClassDesc(static_cast<CK_CLASSID>(i));
|
||||
if (desc == nullptr) continue;
|
||||
|
||||
XContainer::NSXBitArray::Or(result, desc->ToNotify);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Initializations functions
|
||||
|
||||
CKERROR CKStartUp() {
|
||||
static void ComputeParentsTable(CKClassDesc& desc) {
|
||||
// if it has done, do not process it again.
|
||||
if (desc.Done) return;
|
||||
|
||||
// find direct parent
|
||||
CKClassDesc& parent = g_CKClassInfo[static_cast<size_t>(desc.Parent)];
|
||||
if (!parent.IsValid) LIBPANIC("No such CK_CLASSID.");
|
||||
|
||||
// if it is not self inheritance, call recursively
|
||||
if (desc.Self != desc.Parent) {
|
||||
ComputeParentsTable(parent);
|
||||
}
|
||||
|
||||
// copy parent's parents
|
||||
desc.Parents = parent.Parents;
|
||||
// and set self as its parent
|
||||
XContainer::NSXBitArray::Set(desc.Parents, static_cast<CKDWORD>(desc.Self));
|
||||
|
||||
// set derivation level
|
||||
desc.DerivationLevel = parent.DerivationLevel + 1;
|
||||
|
||||
// set done
|
||||
desc.Done = true;
|
||||
}
|
||||
static void ComputeParentsNotifyTable(CKClassDesc& desc) {
|
||||
// if it has done, do not process it again.
|
||||
if (desc.Done) return;
|
||||
|
||||
// find direct parent
|
||||
CKClassDesc& parent = g_CKClassInfo[static_cast<size_t>(desc.Parent)];
|
||||
if (!parent.IsValid) LIBPANIC("No such CK_CLASSID.");
|
||||
|
||||
// if it is not self inheritance, call recursively
|
||||
if (desc.Self != desc.Parent) {
|
||||
ComputeParentsNotifyTable(parent);
|
||||
}
|
||||
|
||||
// copy self notify first
|
||||
desc.CommonToBeNotify = desc.ToBeNotify;
|
||||
// and merge parent notify list
|
||||
XContainer::NSXBitArray::Or(desc.CommonToBeNotify, parent.CommonToBeNotify);
|
||||
|
||||
// set done
|
||||
desc.Done = true;
|
||||
}
|
||||
static void CKBuildClassHierarchyTable() {
|
||||
size_t classCount = g_CKClassInfo.size();
|
||||
|
||||
// ===== Build Inhertance Hierarchy =====
|
||||
// set Done to false and resize inhertance XBitArray
|
||||
for (auto& item : g_CKClassInfo) {
|
||||
if (!item.IsValid) continue;
|
||||
|
||||
item.Done = false;
|
||||
|
||||
XContainer::NSXBitArray::Resize(item.Parents, static_cast<CKDWORD>(classCount));
|
||||
XContainer::NSXBitArray::Resize(item.Children, static_cast<CKDWORD>(classCount));
|
||||
}
|
||||
// compute parents
|
||||
for (auto& item : g_CKClassInfo) {
|
||||
if (!item.IsValid) continue;
|
||||
|
||||
ComputeParentsTable(item);
|
||||
}
|
||||
// compute children by parents table
|
||||
// iterate CKClassDesc::Parents and register it self to gotten parents
|
||||
for (auto& item : g_CKClassInfo) {
|
||||
if (!item.IsValid) continue;
|
||||
|
||||
for (size_t idx = 0; idx < classCount; ++idx) {
|
||||
if (!g_CKClassInfo[idx].IsValid) continue;
|
||||
|
||||
// if this idx is its parent,
|
||||
// add self to parent.
|
||||
if (XContainer::NSXBitArray::IsSet(item.Parents, static_cast<CKDWORD>(idx))) {
|
||||
XContainer::NSXBitArray::Set(g_CKClassInfo[idx].Children, static_cast<CKDWORD>(item.Self));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Register =====
|
||||
// run register
|
||||
for (auto& item : g_CKClassInfo) {
|
||||
if (!item.IsValid || item.RegisterFct == nullptr) continue;
|
||||
item.RegisterFct();
|
||||
}
|
||||
|
||||
// ===== Build Notify Hierarchy =====
|
||||
// set Done to false and resize notify XBitArray
|
||||
for (auto& item : g_CKClassInfo) {
|
||||
if (!item.IsValid) continue;
|
||||
|
||||
item.Done = false;
|
||||
|
||||
XContainer::NSXBitArray::Resize(item.ToBeNotify, static_cast<CKDWORD>(classCount));
|
||||
XContainer::NSXBitArray::Resize(item.CommonToBeNotify, static_cast<CKDWORD>(classCount));
|
||||
XContainer::NSXBitArray::Resize(item.ToNotify, static_cast<CKDWORD>(classCount));
|
||||
}
|
||||
// compute notify
|
||||
for (auto& item : g_CKClassInfo) {
|
||||
if (!item.IsValid) continue;
|
||||
|
||||
ComputeParentsNotifyTable(item);
|
||||
}
|
||||
// compute ToNotify table
|
||||
// for each desc(represented as outter 'for'), iterate all desc(represented as inner 'for'), and check whether its
|
||||
// CommonToBeNotify contain this desc. If true, add checking desc into this desc's ToNotify.
|
||||
for (size_t idx = 0; idx < classCount; ++idx) {
|
||||
if (!g_CKClassInfo[idx].IsValid) continue;
|
||||
|
||||
for (const auto& checkingDesc : g_CKClassInfo) {
|
||||
if(!checkingDesc.IsValid) continue;
|
||||
|
||||
// if checkingDesc's CommonToBeNotify order this desc,
|
||||
// add checking desc to ToNofity
|
||||
if (XContainer::NSXBitArray::IsSet(checkingDesc.CommonToBeNotify, static_cast<CKDWORD>(idx))) {
|
||||
XContainer::NSXBitArray::Set(g_CKClassInfo[idx].ToNotify, static_cast<CKDWORD>(checkingDesc.Self));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void NeedNotificationWrapper(CK_CLASSID thiscid, std::initializer_list<CK_CLASSID> il) {
|
||||
for (auto it = il.begin(); it != il.end(); ++it) {
|
||||
CKClassNeedNotificationFrom(thiscid, *it);
|
||||
}
|
||||
}
|
||||
CKERROR CKStartUp() {
|
||||
// reserve class info array.
|
||||
g_CKClassInfo.reserve(static_cast<size_t>(CK_CLASSID::CKCID_MAXCLASSID));
|
||||
|
||||
// todo: add class type registrations
|
||||
#define EasyClassReg(clsname, cid, parentCid, strName) \
|
||||
CKClassRegister(cid, parentCid, \
|
||||
nullptr, \
|
||||
[](CKContext* ctx, CK_ID id, CKSTRING name) -> ObjImpls::CKObject* { return new clsname(ctx, id, name); }, \
|
||||
[](CKContext* ctx, ObjImpls::CKObject* obj) -> void { delete obj; }, \
|
||||
[]() -> CKSTRING { return strName; });
|
||||
#define EasyClassRegWithNotify(clsname, cid, parentCid, strName, notifyCids) \
|
||||
CKClassRegister(cid, parentCid, \
|
||||
[]() -> void { NeedNotificationWrapper(cid, notifyCids); }, \
|
||||
[](CKContext* ctx, CK_ID id, CKSTRING name) -> ObjImpls::CKObject* { return new clsname(ctx, id, name); }, \
|
||||
[](CKContext* ctx, ObjImpls::CKObject* obj) -> void { delete obj; }, \
|
||||
[]() -> CKSTRING { return strName; });
|
||||
@ -267,7 +374,7 @@ CKClassRegister(cid, parentCid, \
|
||||
EasyClassReg(ObjImpls::CKObject, CK_CLASSID::CKCID_OBJECT, CK_CLASSID::CKCID_OBJECT, "Basic Object");
|
||||
EasyClassReg(ObjImpls::CKSceneObject, CK_CLASSID::CKCID_SCENEOBJECT, CK_CLASSID::CKCID_OBJECT, "Scene Object");
|
||||
EasyClassReg(ObjImpls::CKBeObject, CK_CLASSID::CKCID_BEOBJECT, CK_CLASSID::CKCID_SCENEOBJECT, "Behavioral Object");
|
||||
EasyClassReg(ObjImpls::CKGroup, CK_CLASSID::CKCID_GROUP, CK_CLASSID::CKCID_BEOBJECT, "Group");
|
||||
EasyClassRegWithNotify(ObjImpls::CKGroup, CK_CLASSID::CKCID_GROUP, CK_CLASSID::CKCID_BEOBJECT, "Group", { CK_CLASSID::CKCID_BEOBJECT });
|
||||
EasyClassReg(ObjImpls::CKRenderObject, CK_CLASSID::CKCID_RENDEROBJECT, CK_CLASSID::CKCID_BEOBJECT, "Render Object");
|
||||
EasyClassReg(ObjImpls::CK3dEntity, CK_CLASSID::CKCID_3DENTITY, CK_CLASSID::CKCID_RENDEROBJECT, "3D Entity");
|
||||
EasyClassReg(ObjImpls::CK3dObject, CK_CLASSID::CKCID_3DOBJECT, CK_CLASSID::CKCID_3DENTITY, "3D Object");
|
||||
@ -275,6 +382,7 @@ CKClassRegister(cid, parentCid, \
|
||||
EasyClassReg(ObjImpls::CKMaterial, CK_CLASSID::CKCID_MATERIAL, CK_CLASSID::CKCID_BEOBJECT, "Material");
|
||||
|
||||
#undef EasyClassReg
|
||||
#undef EasyClassRegWithNotify
|
||||
|
||||
CKBuildClassHierarchyTable();
|
||||
|
||||
|
@ -74,7 +74,7 @@ namespace LibCmo::CK2 {
|
||||
|
||||
// ========== Class registration utilities ==========
|
||||
|
||||
//using CKClassRegisterFct = std::function<void()>;
|
||||
using CKClassRegisterFct = std::function<void()>;
|
||||
using CKClassCreationFct = std::function<ObjImpls::CKObject* (CKContext*, CK_ID, CKSTRING)>;
|
||||
using CKClassReleaseFct = std::function<void(CKContext*, ObjImpls::CKObject*)>;
|
||||
using CKClassNameFct = std::function<CKSTRING()>;
|
||||
@ -87,7 +87,7 @@ namespace LibCmo::CK2 {
|
||||
// Initialized upon class registration
|
||||
CK_CLASSID Self;
|
||||
CK_CLASSID Parent; // Class Identifier of parent class
|
||||
//CKClassRegisterFct RegisterFct; // Pointer to Class Specific Registration function
|
||||
CKClassRegisterFct RegisterFct; // Pointer to Class Specific Registration function
|
||||
CKClassCreationFct CreationFct; // Pointer to Class instance creation function
|
||||
CKClassReleaseFct ReleaseFct; // Pointer to Class instance release function
|
||||
CKClassNameFct NameFct; // Pointer to Class name function
|
||||
@ -106,26 +106,27 @@ namespace LibCmo::CK2 {
|
||||
CKINT DerivationLevel; // O => CKObject , etc..
|
||||
XContainer::XBitArray Parents; // Bit Mask of parents classes
|
||||
XContainer::XBitArray Children; // Bit Mask of children classes
|
||||
//XContainer::XBitArray ToBeNotify; // Mask for Classes that should warn the objects of this class when they are deleted
|
||||
//XContainer::XBitArray CommonToBeNotify; // idem but merged with sub classes masks
|
||||
//XContainer::XSArray<CK_CLASSID> ToNotify; // List of ClassID to notify when an object of this class is deleted (inverse of ToBeNotify)
|
||||
XContainer::XBitArray ToBeNotify; // User specified notify list, only for current class.
|
||||
XContainer::XBitArray CommonToBeNotify; // Same as ToBeNotify, but merging all parents' notify list.
|
||||
XContainer::XBitArray ToNotify; // The ClassID to notify when an object of this class is deleted (inverse of ToBeNotify)
|
||||
|
||||
CKClassDesc() :
|
||||
IsValid(false),
|
||||
Done(false),
|
||||
Self(CK_CLASSID::CKCID_OBJECT), Parent(CK_CLASSID::CKCID_OBJECT),
|
||||
CreationFct(nullptr), ReleaseFct(nullptr), NameFct(nullptr),
|
||||
RegisterFct(nullptr), CreationFct(nullptr), ReleaseFct(nullptr), NameFct(nullptr),
|
||||
DerivationLevel(0),
|
||||
Parents(), Children()
|
||||
Parents(), Children(), ToBeNotify(), CommonToBeNotify()
|
||||
{}
|
||||
LIBCMO_DEFAULT_COPY_MOVE(CKClassDesc);
|
||||
};
|
||||
|
||||
// ========== CKClass Registration ==========
|
||||
|
||||
void CKClassNeedNotificationFrom(CK_CLASSID listener, CK_CLASSID listenTo);
|
||||
CK_CLASSID CKClassGetNewIdentifier();
|
||||
void CKClassRegister(CK_CLASSID cid, CK_CLASSID parentCid,
|
||||
CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct);
|
||||
CKClassRegisterFct regFct, CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct);
|
||||
|
||||
// ========== Class Hierarchy Management ==========
|
||||
|
||||
@ -137,6 +138,21 @@ namespace LibCmo::CK2 {
|
||||
CK_CLASSID CKGetParentClassID(CK_CLASSID child);
|
||||
CK_CLASSID CKGetCommonParent(CK_CLASSID cid1, CK_CLASSID cid2);
|
||||
|
||||
/**
|
||||
* @brief Check whether 'listener' need notified by the deletion of 'deletedObjCid'
|
||||
* @param listener
|
||||
* @param deletedObjCid
|
||||
* @return true if need notify
|
||||
*/
|
||||
bool CKIsNeedNotify(CK_CLASSID listener, CK_CLASSID deletedObjCid);
|
||||
/**
|
||||
* @brief Get all object cid need to be notified when 'delObjCids' matched objects are deleting.
|
||||
* @param delObjCids
|
||||
* @param cidCount
|
||||
* @return
|
||||
*/
|
||||
XContainer::XBitArray CKGetAllNotifyClassID(const XContainer::XBitArray& delObjCids);
|
||||
|
||||
// ========== Initializations functions ==========
|
||||
CKERROR CKStartUp();
|
||||
CKERROR CKShutdown();
|
||||
|
@ -72,30 +72,73 @@ namespace LibCmo::CK2::MgrImpls {
|
||||
}
|
||||
|
||||
void CKObjectManager::DestroyObjects(CK_ID* ids, CKDWORD count) {
|
||||
// notice pre
|
||||
// pre notice manager
|
||||
m_Context->ExecuteManagersOnSequenceToBeDeleted(ids, count);
|
||||
|
||||
// collect object data
|
||||
// remove invalid object first, set them to be deleted
|
||||
// collection deleted object class ids
|
||||
XContainer::XObjectArray validObjIds;
|
||||
XContainer::XBitArray cids;
|
||||
for (CKDWORD i = 0; i < count; ++i) {
|
||||
CKDWORD off = Id2Offset(ids[i]);
|
||||
if (off >= m_ObjectsList.size()) continue;
|
||||
|
||||
// get object and its classid for future use
|
||||
ObjImpls::CKObject* obj = m_ObjectsList[off];
|
||||
if (obj == nullptr) continue;
|
||||
CK_CLASSID cls = obj->GetClassID();
|
||||
|
||||
// set to be deleted
|
||||
CK_OBJECT_FLAGS objflag = obj->GetObjectFlags();
|
||||
EnumsHelper::Add(objflag, CK_OBJECT_FLAGS::CK_OBJECT_TOBEDELETED);
|
||||
obj->SetObjectFlags(objflag);
|
||||
|
||||
// collect class id
|
||||
XContainer::NSXBitArray::Set(cids, static_cast<CKDWORD>(obj->GetClassID()));
|
||||
|
||||
// add into list
|
||||
validObjIds.emplace_back(ids[i]);
|
||||
}
|
||||
|
||||
// then remove deleted object from m_ObjectListByClass
|
||||
// because we have set to be deleted flag.
|
||||
for (size_t i = 0; i < m_ObjectsListByClass.size(); ++i) {
|
||||
if (!XContainer::NSXBitArray::IsSet(cids, static_cast<CKDWORD>(i)))
|
||||
continue;
|
||||
XContainer::NSXObjectArray::PreDeletedCheck(m_ObjectsListByClass[i], m_Context);
|
||||
}
|
||||
|
||||
// use collected cid to get all class ids which need receive notify
|
||||
// and use m_ObjectListByClass to notify them
|
||||
XContainer::XBitArray notifyCids = CKGetAllNotifyClassID(cids);
|
||||
for (size_t i = 0; i < m_ObjectsListByClass.size(); ++i) {
|
||||
if (!XContainer::NSXBitArray::IsSet(notifyCids, static_cast<CKDWORD>(i)))
|
||||
continue;
|
||||
for (auto& objid : m_ObjectsListByClass[i]) {
|
||||
m_ObjectsList[Id2Offset(objid)]->CheckPreDeletion();
|
||||
}
|
||||
}
|
||||
|
||||
// then free all valid object
|
||||
for (const auto& objid : validObjIds) {
|
||||
CKDWORD off = Id2Offset(objid);
|
||||
ObjImpls::CKObject* obj = m_ObjectsList[off];
|
||||
|
||||
// free it
|
||||
InternalDestroy(obj);
|
||||
|
||||
|
||||
// return its allocated id.
|
||||
// and dec count
|
||||
m_ObjectsList[off] = nullptr;
|
||||
m_ReturnedObjectOffsets.emplace_back(off);
|
||||
--m_ObjectCount;
|
||||
}
|
||||
|
||||
// remove from classid indexed list
|
||||
std::erase(m_ObjectsListByClass[static_cast<size_t>(cls)], ids[i]);
|
||||
|
||||
// run post deletion for notify object
|
||||
for (size_t i = 0; i < m_ObjectsListByClass.size(); ++i) {
|
||||
if (!XContainer::NSXBitArray::IsSet(notifyCids, static_cast<CKDWORD>(i)))
|
||||
continue;
|
||||
for (auto& objid : m_ObjectsListByClass[i]) {
|
||||
m_ObjectsList[Id2Offset(objid)]->CheckPostDeletion();
|
||||
}
|
||||
}
|
||||
|
||||
// notice post
|
||||
@ -156,6 +199,8 @@ namespace LibCmo::CK2::MgrImpls {
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma region Object Check
|
||||
|
||||
bool CKObjectManager::IsObjectSafe(CK_ID objid) {
|
||||
CKDWORD off = Id2Offset(objid);
|
||||
if (off >= m_ObjectsList.size()) return false;
|
||||
@ -171,6 +216,10 @@ namespace LibCmo::CK2::MgrImpls {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Special Functions
|
||||
|
||||
CKDWORD CKObjectManager::AllocateGroupGlobalIndex() {
|
||||
// try find first non-true position
|
||||
@ -182,7 +231,7 @@ namespace LibCmo::CK2::MgrImpls {
|
||||
}
|
||||
|
||||
// set to occupy
|
||||
m_GroupGlobalIndex[index] = true;
|
||||
XContainer::NSXBitArray::Set(m_GroupGlobalIndex, index);
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -194,7 +243,7 @@ namespace LibCmo::CK2::MgrImpls {
|
||||
m_SceneGlobalIndex.resize(m_SceneGlobalIndex.size() + 1);
|
||||
}
|
||||
|
||||
m_SceneGlobalIndex[index] = true;
|
||||
XContainer::NSXBitArray::Set(m_SceneGlobalIndex, index);
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -202,13 +251,15 @@ namespace LibCmo::CK2::MgrImpls {
|
||||
// check position
|
||||
if (id >= m_GroupGlobalIndex.size()) return;
|
||||
// set value
|
||||
m_GroupGlobalIndex[id] = false;
|
||||
XContainer::NSXBitArray::Unset(m_GroupGlobalIndex, id);
|
||||
}
|
||||
|
||||
void CKObjectManager::FreeSceneGlobalIndex(CKDWORD id) {
|
||||
// same as group
|
||||
if (id >= m_SceneGlobalIndex.size()) return;
|
||||
m_SceneGlobalIndex[id] = false;
|
||||
XContainer::NSXBitArray::Unset(m_SceneGlobalIndex, id);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
}
|
||||
|
@ -37,13 +37,15 @@ namespace LibCmo::CK2::ObjImpls {
|
||||
bool CKBeObject::IsInGroup(CKGroup* group) {
|
||||
if (group == nullptr) return false;
|
||||
CKDWORD idx = group->GetGroupIndex();
|
||||
if (idx >= m_Groups.size()) return false;
|
||||
return m_Groups[idx];
|
||||
return XContainer::NSXBitArray::IsSet(m_Groups, idx);
|
||||
}
|
||||
|
||||
void CKBeObject::ExplicitSetGroup(CKDWORD pos, bool val) {
|
||||
if (pos >= m_Groups.size()) m_Groups.resize(pos + 1);
|
||||
m_Groups[pos] = val;
|
||||
if (val) {
|
||||
XContainer::NSXBitArray::Set(m_Groups, pos);
|
||||
} else {
|
||||
XContainer::NSXBitArray::Unset(m_Groups, pos);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,8 @@
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
void CKObject::CheckPreDeletion() {}
|
||||
void CKObject::CheckPostDeletion() {}
|
||||
|
||||
void CKObject::PreSave(CKFileVisitor* file, CKDWORD flags) {}
|
||||
|
||||
|
@ -68,6 +68,8 @@ namespace LibCmo::CK2::ObjImpls {
|
||||
virtual CK_CLASSID GetClassID(void) {
|
||||
return CK_CLASSID::CKCID_OBJECT;
|
||||
}
|
||||
virtual void CheckPreDeletion();
|
||||
virtual void CheckPostDeletion();
|
||||
virtual void PreSave(CKFileVisitor* file, CKDWORD flags);
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags);
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file);
|
||||
|
@ -75,6 +75,10 @@ namespace LibCmo {
|
||||
#define LIBPANIC(msg) LibCmo::LibPanic(__LINE__, __FILE__, msg);
|
||||
|
||||
namespace EnumsHelper {
|
||||
|
||||
/**
|
||||
* @brief Return 'e1 | e2 | ... | en'
|
||||
*/
|
||||
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||
inline TEnum Merge(std::initializer_list<TEnum> il) {
|
||||
std::underlying_type_t<TEnum> result = 0;
|
||||
@ -84,26 +88,41 @@ namespace LibCmo {
|
||||
return static_cast<TEnum>(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return '~(e)'
|
||||
*/
|
||||
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||
inline TEnum Inv(TEnum e) {
|
||||
return static_cast<TEnum>(~(static_cast<std::underlying_type_t<TEnum>>(e)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Operate e1 &= (~e2)
|
||||
*/
|
||||
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||
inline void Rm(TEnum& e1, TEnum e2) {
|
||||
e1 = static_cast<TEnum>(static_cast<std::underlying_type_t<TEnum>>(e1) & static_cast<std::underlying_type_t<TEnum>>(Inv(e2)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operate e1 &= e2
|
||||
*/
|
||||
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||
inline void Mask(TEnum& e1, TEnum e2) {
|
||||
e1 = static_cast<TEnum>(static_cast<std::underlying_type_t<TEnum>>(e1) & static_cast<std::underlying_type_t<TEnum>>(e2));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Operate e1 |= e2
|
||||
*/
|
||||
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||
inline void Add(TEnum& e1, TEnum e2) {
|
||||
e1 = static_cast<TEnum>(static_cast<std::underlying_type_t<TEnum>>(e1) | static_cast<std::underlying_type_t<TEnum>>(e2));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return 'bool(e1 & e2)'
|
||||
*/
|
||||
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||
inline bool Has(TEnum e, TEnum probe) {
|
||||
return static_cast<bool>(static_cast<std::underlying_type_t<TEnum>>(e) & static_cast<std::underlying_type_t<TEnum>>(probe));
|
||||
|
@ -8,6 +8,37 @@ namespace LibCmo::XContainer {
|
||||
|
||||
namespace NSXBitArray {
|
||||
|
||||
void Resize(XBitArray& ba, CKDWORD newsize) {
|
||||
ba.resize(newsize, false);
|
||||
}
|
||||
|
||||
void Or(XBitArray& thisba, const XBitArray& thatba) {
|
||||
if (thisba.size() < thatba.size()) {
|
||||
Resize(thisba, static_cast<CKDWORD>(thatba.size()));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < thisba.size(); ++i) {
|
||||
thisba[i] = thisba[i] || thatba[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool IsSet(const XBitArray& ba, CKDWORD n) {
|
||||
if (n >= ba.size()) return false;
|
||||
return ba[n];
|
||||
}
|
||||
|
||||
void Set(XBitArray& ba, CKDWORD n) {
|
||||
if (n >= ba.size()) {
|
||||
ba.resize(n + 1);
|
||||
}
|
||||
ba[n] = true;
|
||||
}
|
||||
|
||||
void Unset(XBitArray& ba, CKDWORD n) {
|
||||
if (n >= ba.size()) return;
|
||||
ba[n] = false;
|
||||
}
|
||||
|
||||
template<bool _Cond>
|
||||
bool GeneralGetBitPosition(const XBitArray& ba, CKDWORD n, CKDWORD& got) {
|
||||
CKDWORD counter = 0;
|
||||
@ -93,6 +124,21 @@ namespace LibCmo::XContainer {
|
||||
return GeneralXArrayCheck_ItemCheck<CK2::CK_ID, false>(item, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void PreDeletedCheck(XList<CK2::CK_ID>& objarray, CK2::CKContext* ctx) {
|
||||
if (ctx == nullptr) return;
|
||||
std::erase_if(objarray, [ctx](const CK2::CK_ID& item) -> bool {
|
||||
return GeneralXArrayCheck_ItemCheck<CK2::CK_ID, true>(item, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
void PostDeletedCheck(XList<CK2::CK_ID>& objarray, CK2::CKContext* ctx) {
|
||||
if (ctx == nullptr) return;
|
||||
std::erase_if(objarray, [ctx](const CK2::CK_ID& item) -> bool {
|
||||
return GeneralXArrayCheck_ItemCheck<CK2::CK_ID, false>(item, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
namespace NSXObjectPointerArray {
|
||||
|
@ -80,15 +80,50 @@ namespace LibCmo::XContainer {
|
||||
// ========== Patch Section ==========
|
||||
|
||||
namespace NSXBitArray {
|
||||
|
||||
/**
|
||||
* @brief Resize XBitArray to the new size. Initial value is false.
|
||||
* @param ba The XBitArray
|
||||
* @param newsize New Size
|
||||
*/
|
||||
void Resize(XBitArray& ba, CKDWORD newsize);
|
||||
|
||||
/**
|
||||
* @brief Returns the position of the n-th set(1) bit
|
||||
* @return false if not found.
|
||||
* @brief Merge other XBitArray to this XBitArray with OR condition.
|
||||
* This XBitArray will be resized at least equal with merged XBitArray if its size is lower than merged XBitArray
|
||||
* @param thisba This XBitArray
|
||||
* @param thatba Other XBitArray will be merged.
|
||||
*/
|
||||
void Or(XBitArray& thisba, const XBitArray& thatba);
|
||||
|
||||
/**
|
||||
* @brief Check whether bit flag is set.
|
||||
* @param ba The XBitArray
|
||||
* @param n The check position.
|
||||
* @return True if set. False if not set or out of range.
|
||||
*/
|
||||
bool IsSet(const XBitArray& ba, CKDWORD n);
|
||||
/**
|
||||
* @brief Set specified position to true in XBitArray. Auto resize if no space to set.
|
||||
* @param ba The XBitArray
|
||||
* @param n The set position.
|
||||
*/
|
||||
void Set(XBitArray& ba, CKDWORD n);
|
||||
/**
|
||||
* @brief Unset specified position to true in XBitArray. If out of range, simply return.
|
||||
* @param ba The XBitArray
|
||||
* @param n The unset position.
|
||||
*/
|
||||
void Unset(XBitArray& ba, CKDWORD n);
|
||||
|
||||
/**
|
||||
* @brief Returns the position of the n-th set(1) bit
|
||||
* @return false if not found.
|
||||
*/
|
||||
bool GetSetBitPosition(const XBitArray& ba, CKDWORD n, CKDWORD& got);
|
||||
/**
|
||||
* @brief Returns the position of the n-th unset(0) bit
|
||||
* @return false if not found.
|
||||
* @brief Returns the position of the n-th unset(0) bit
|
||||
* @return false if not found.
|
||||
*/
|
||||
bool GetUnsetBitPosition(const XBitArray& ba, CKDWORD n, CKDWORD& got);
|
||||
|
||||
@ -126,6 +161,20 @@ namespace LibCmo::XContainer {
|
||||
* @param ctx
|
||||
*/
|
||||
void PostDeletedCheck(XObjectArray& objarray, CK2::CKContext* ctx);
|
||||
|
||||
/**
|
||||
* @brief Check Object pointer validation and remove invalid pointers before deletion.
|
||||
* @param objarray
|
||||
* @param ctx
|
||||
*/
|
||||
void PreDeletedCheck(XList<CK2::CK_ID>& objarray, CK2::CKContext* ctx);
|
||||
/**
|
||||
* @brief Check Object pointer validation and remove invalid pointers after deletion.
|
||||
* @param objarray
|
||||
* @param ctx
|
||||
* @remark The performance of this function is extremely low. Use it carefully.
|
||||
*/
|
||||
void PostDeletedCheck(XList<CK2::CK_ID>& objarray, CK2::CKContext* ctx);
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user