2023-08-22 15:30:26 +08:00
|
|
|
#include "CKContext.hpp"
|
2023-08-26 16:37:26 +08:00
|
|
|
#include "ObjImpls/CKObject.hpp"
|
2023-09-05 22:23:05 +08:00
|
|
|
#include "MgrImpls/CKBaseManager.hpp"
|
|
|
|
#include "MgrImpls/CKObjectManager.hpp"
|
|
|
|
#include "MgrImpls/CKPathManager.hpp"
|
2023-03-04 14:08:16 +08:00
|
|
|
#include <cstdarg>
|
2023-02-25 22:58:28 +08:00
|
|
|
|
2023-02-26 21:48:03 +08:00
|
|
|
namespace LibCmo::CK2 {
|
2023-02-25 22:58:28 +08:00
|
|
|
|
2023-09-01 12:19:06 +08:00
|
|
|
#pragma region Ctor Dtor
|
|
|
|
|
|
|
|
CKContext::CKContext() :
|
2023-09-05 22:23:05 +08:00
|
|
|
// setup manager
|
|
|
|
m_ManagerList(),
|
|
|
|
m_ObjectManager(nullptr), m_PathManager(nullptr),
|
2023-09-06 10:42:23 +08:00
|
|
|
// setup object cache
|
|
|
|
m_ObjectCache(), m_ObjectPointerCache(),
|
2023-09-05 22:23:05 +08:00
|
|
|
// setup file save/load options
|
2023-09-06 10:42:23 +08:00
|
|
|
m_CompressionLevel(5),
|
|
|
|
m_FileWriteMode(CK_FILE_WRITEMODE::CKFILE_UNCOMPRESSED),
|
2023-09-05 22:23:05 +08:00
|
|
|
m_GlobalImagesSaveOptions(CK_TEXTURE_SAVEOPTIONS::CKTEXTURE_RAWDATA),
|
|
|
|
m_GlobalSoundsSaveOptions(CK_SOUND_SAVEOPTIONS::CKSOUND_EXTERNAL),
|
2023-09-07 21:57:48 +08:00
|
|
|
m_GlobalImagesSaveFormat(),
|
2023-09-05 22:23:05 +08:00
|
|
|
// misc init
|
2023-09-06 10:42:23 +08:00
|
|
|
m_NameEncoding(),
|
|
|
|
m_OutputCallback(nullptr) {
|
2023-09-05 22:23:05 +08:00
|
|
|
|
2023-09-07 21:57:48 +08:00
|
|
|
// setup save format
|
2024-08-23 11:28:49 +08:00
|
|
|
m_GlobalImagesSaveFormat.m_Ext.SetExt(u8"bmp");
|
2023-09-07 21:57:48 +08:00
|
|
|
|
2023-09-05 22:23:05 +08:00
|
|
|
// setup managers
|
|
|
|
m_ObjectManager = new MgrImpls::CKObjectManager(this);
|
|
|
|
m_ManagerList.emplace_back(m_ObjectManager);
|
|
|
|
m_PathManager = new MgrImpls::CKPathManager(this);
|
|
|
|
m_ManagerList.emplace_back(m_PathManager);
|
2023-09-01 12:19:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CKContext::~CKContext() {
|
2023-09-05 22:23:05 +08:00
|
|
|
// reset context
|
2023-09-04 22:58:53 +08:00
|
|
|
ClearAll();
|
2023-09-05 22:23:05 +08:00
|
|
|
// free all manager
|
|
|
|
for (auto& mgrptr : m_ManagerList) {
|
|
|
|
delete mgrptr;
|
|
|
|
}
|
2024-08-23 11:28:49 +08:00
|
|
|
// free encoding
|
|
|
|
this->ClearEncoding();
|
2023-09-01 12:19:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
2023-09-05 22:23:05 +08:00
|
|
|
#pragma region Engine runtime
|
2023-08-23 16:04:58 +08:00
|
|
|
|
2023-09-04 22:58:53 +08:00
|
|
|
void CKContext::ClearAll() {
|
2023-09-05 22:23:05 +08:00
|
|
|
// pre clear all
|
|
|
|
ExecuteManagersOnPreClearAll();
|
|
|
|
|
|
|
|
// order object manager clear all objects
|
|
|
|
m_ObjectManager->DestroyAllObjects();
|
|
|
|
|
|
|
|
// post clear all
|
|
|
|
ExecuteManagersOnPostClearAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region Objects Management / Access
|
|
|
|
|
|
|
|
ObjImpls::CKObject* CKContext::CreateObject(CK_CLASSID cls, CKSTRING name, CK_OBJECTCREATION_OPTIONS options, CK_CREATIONMODE* res) {
|
|
|
|
return m_ObjectManager->CreateObject(cls, name, options, res);
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjImpls::CKObject* CKContext::GetObject(CK_ID ObjID) {
|
|
|
|
return m_ObjectManager->GetObject(ObjID);
|
|
|
|
}
|
|
|
|
|
|
|
|
CKDWORD CKContext::GetObjectCount() {
|
|
|
|
return m_ObjectManager->GetObjectCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::DestroyObject(ObjImpls::CKObject* obj) {
|
|
|
|
CK_ID id = obj->GetID();
|
|
|
|
return m_ObjectManager->DestroyObjects(&id, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::DestroyObject(CK_ID id) {
|
|
|
|
return m_ObjectManager->DestroyObjects(&id, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::DestroyObjects(CK_ID* obj_ids, CKDWORD Count) {
|
|
|
|
return m_ObjectManager->DestroyObjects(obj_ids, Count);
|
|
|
|
}
|
|
|
|
|
2023-09-06 10:42:23 +08:00
|
|
|
ObjImpls::CKObject* GeneralPrevFinder(XContainer::XObjectPointerArray& objptrs, ObjImpls::CKObject* previous) {
|
2023-09-07 16:27:41 +08:00
|
|
|
if (objptrs.empty()) return nullptr;
|
|
|
|
|
|
|
|
if (previous == nullptr) {
|
|
|
|
return objptrs.front();
|
|
|
|
} else {
|
|
|
|
auto finder = std::find(objptrs.begin(), objptrs.end(), previous);
|
|
|
|
if (finder == objptrs.end()) return nullptr;
|
|
|
|
++finder;
|
|
|
|
if (finder == objptrs.end()) return nullptr;
|
|
|
|
return *finder;
|
|
|
|
}
|
2023-09-05 22:23:05 +08:00
|
|
|
}
|
2023-09-06 10:42:23 +08:00
|
|
|
ObjImpls::CKObject* CKContext::GetObjectByName(CKSTRING name, ObjImpls::CKObject* previous) {
|
|
|
|
if (name == nullptr) return nullptr;
|
|
|
|
if (previous == nullptr) {
|
|
|
|
m_ObjectPointerCache = m_ObjectManager->GetObjectByNameAndClass(name, CK_CLASSID::CKCID_OBJECT, true);
|
|
|
|
}
|
|
|
|
return GeneralPrevFinder(m_ObjectPointerCache, previous);
|
|
|
|
}
|
2023-09-05 22:23:05 +08:00
|
|
|
|
|
|
|
ObjImpls::CKObject* CKContext::GetObjectByNameAndClass(CKSTRING name, CK_CLASSID cid, ObjImpls::CKObject* previous) {
|
|
|
|
if (name == nullptr) return nullptr;
|
2023-09-06 10:42:23 +08:00
|
|
|
if (previous == nullptr) {
|
|
|
|
m_ObjectPointerCache = m_ObjectManager->GetObjectByNameAndClass(name, cid, false);
|
|
|
|
}
|
|
|
|
return GeneralPrevFinder(m_ObjectPointerCache, previous);
|
2023-09-05 22:23:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ObjImpls::CKObject* CKContext::GetObjectByNameAndParentClass(CKSTRING name, CK_CLASSID pcid, ObjImpls::CKObject* previous) {
|
|
|
|
if (name == nullptr) return nullptr;
|
2023-09-06 10:42:23 +08:00
|
|
|
if (previous == nullptr) {
|
|
|
|
m_ObjectPointerCache = m_ObjectManager->GetObjectByNameAndClass(name, pcid, true);
|
|
|
|
}
|
|
|
|
return GeneralPrevFinder(m_ObjectPointerCache, previous);
|
2023-09-05 22:23:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const XContainer::XObjectPointerArray CKContext::GetObjectListByType(CK_CLASSID cid, bool derived) {
|
|
|
|
return m_ObjectManager->GetObjectByNameAndClass(nullptr, cid, derived);
|
|
|
|
}
|
2023-08-23 16:04:58 +08:00
|
|
|
|
2023-09-05 22:23:05 +08:00
|
|
|
CKDWORD CKContext::GetObjectsCountByClassID(CK_CLASSID cid) {
|
|
|
|
auto result = m_ObjectManager->GetObjectByNameAndClass(nullptr, cid, false);
|
2023-09-06 10:42:23 +08:00
|
|
|
|
|
|
|
m_ObjectCache.clear();
|
|
|
|
for (auto& obj : result) {
|
|
|
|
m_ObjectCache.emplace_back(obj->GetID());
|
|
|
|
}
|
|
|
|
|
|
|
|
return static_cast<CKDWORD>(m_ObjectCache.size());
|
2023-09-05 22:23:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CK_ID* CKContext::GetObjectsListByClassID(CK_CLASSID cid) {
|
2023-09-06 10:42:23 +08:00
|
|
|
return m_ObjectCache.data();
|
2023-08-27 22:14:02 +08:00
|
|
|
}
|
|
|
|
|
2023-08-23 16:04:58 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
2023-09-05 22:23:05 +08:00
|
|
|
#pragma region Common Managers
|
2023-09-06 10:42:23 +08:00
|
|
|
|
2023-09-05 22:23:05 +08:00
|
|
|
MgrImpls::CKObjectManager* CKContext::GetObjectManager() {
|
|
|
|
return m_ObjectManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
MgrImpls::CKPathManager* CKContext::GetPathManager() {
|
|
|
|
return m_PathManager;
|
|
|
|
}
|
|
|
|
|
2023-09-04 22:58:53 +08:00
|
|
|
CKDWORD CKContext::GetManagerCount() {
|
2023-09-22 22:31:51 +08:00
|
|
|
return static_cast<CKDWORD>(m_ManagerList.size());
|
2023-08-28 14:18:58 +08:00
|
|
|
}
|
|
|
|
|
2023-09-04 22:58:53 +08:00
|
|
|
MgrImpls::CKBaseManager* CKContext::GetManager(CKDWORD index) {
|
|
|
|
if (index >= m_ManagerList.size()) return nullptr;
|
|
|
|
return m_ManagerList[index];
|
2023-08-28 14:18:58 +08:00
|
|
|
}
|
|
|
|
|
2023-09-05 22:23:05 +08:00
|
|
|
void CKContext::ExecuteManagersOnPreClearAll() {
|
|
|
|
ExecuteManagersGeneral([](MgrImpls::CKBaseManager* mgr) -> void {
|
|
|
|
mgr->PreClearAll();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::ExecuteManagersOnPostClearAll() {
|
|
|
|
ExecuteManagersGeneral([](MgrImpls::CKBaseManager* mgr) -> void {
|
|
|
|
mgr->PostClearAll();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::ExecuteManagersOnSequenceToBeDeleted(const CK_ID* objids, CKDWORD count) {
|
|
|
|
ExecuteManagersGeneral([objids, count](MgrImpls::CKBaseManager* mgr) -> void {
|
|
|
|
mgr->SequenceToBeDeleted(objids, count);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::ExecuteManagersOnSequenceDeleted(const CK_ID* objids, CKDWORD count) {
|
|
|
|
ExecuteManagersGeneral([objids, count](MgrImpls::CKBaseManager* mgr) -> void {
|
|
|
|
mgr->SequenceDeleted(objids, count);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::ExecuteManagersGeneral(std::function<void(MgrImpls::CKBaseManager*)> fct) {
|
|
|
|
for (auto& mgrptr : m_ManagerList) {
|
|
|
|
fct(mgrptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-28 14:18:58 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region File Save/Load Options
|
|
|
|
|
|
|
|
void CKContext::SetCompressionLevel(CKINT level) {
|
|
|
|
if (level > 0 && level < 10) {
|
|
|
|
m_CompressionLevel = level;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CKINT CKContext::GetCompressionLevel() {
|
|
|
|
return m_CompressionLevel;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::SetFileWriteMode(CK_FILE_WRITEMODE mode) {
|
|
|
|
m_FileWriteMode = mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
CK_FILE_WRITEMODE CKContext::GetFileWriteMode() {
|
|
|
|
return m_FileWriteMode;
|
|
|
|
}
|
|
|
|
|
2023-09-05 22:23:05 +08:00
|
|
|
CK_TEXTURE_SAVEOPTIONS CKContext::GetGlobalImagesSaveOptions() {
|
|
|
|
return m_GlobalImagesSaveOptions;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::SetGlobalImagesSaveOptions(CK_TEXTURE_SAVEOPTIONS Options) {
|
|
|
|
if (Options != CK_TEXTURE_SAVEOPTIONS::CKTEXTURE_USEGLOBAL) {
|
|
|
|
m_GlobalImagesSaveOptions = Options;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-07 21:57:48 +08:00
|
|
|
const CKBitmapProperties& CKContext::GetGlobalImagesSaveFormat() {
|
2023-09-05 22:23:05 +08:00
|
|
|
return m_GlobalImagesSaveFormat;
|
|
|
|
}
|
|
|
|
|
2023-09-07 21:57:48 +08:00
|
|
|
void CKContext::SetGlobalImagesSaveFormat(const CKBitmapProperties& Format) {
|
|
|
|
m_GlobalImagesSaveFormat = Format;
|
2023-09-05 22:23:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CK_SOUND_SAVEOPTIONS CKContext::GetGlobalSoundsSaveOptions() {
|
|
|
|
return m_GlobalSoundsSaveOptions;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::SetGlobalSoundsSaveOptions(CK_SOUND_SAVEOPTIONS Options) {
|
|
|
|
if (Options != CK_SOUND_SAVEOPTIONS::CKSOUND_USEGLOBAL) {
|
|
|
|
m_GlobalSoundsSaveOptions = Options;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-28 14:18:58 +08:00
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
2023-08-23 16:04:58 +08:00
|
|
|
#pragma region Output utilities
|
2023-02-28 11:35:54 +08:00
|
|
|
|
2023-08-23 16:04:58 +08:00
|
|
|
void CKContext::OutputToConsole(CKSTRING str) {
|
|
|
|
if (m_OutputCallback == nullptr) return;
|
2024-08-23 11:28:49 +08:00
|
|
|
if (str == nullptr) return;
|
2023-08-23 16:04:58 +08:00
|
|
|
m_OutputCallback(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CKContext::OutputToConsoleEx(CKSTRING fmt, ...) {
|
|
|
|
if (m_OutputCallback == nullptr) return;
|
2024-08-23 11:28:49 +08:00
|
|
|
if (fmt == nullptr) return;
|
2023-02-26 21:48:03 +08:00
|
|
|
|
2023-02-25 22:58:28 +08:00
|
|
|
va_list argptr;
|
|
|
|
va_start(argptr, fmt);
|
2023-09-16 18:31:25 +08:00
|
|
|
XContainer::XString result;
|
2024-08-23 11:28:49 +08:00
|
|
|
YYCC::StringHelper::VPrintf(fmt, argptr);
|
2023-02-25 22:58:28 +08:00
|
|
|
va_end(argptr);
|
2023-02-26 21:48:03 +08:00
|
|
|
|
2023-10-08 10:42:07 +08:00
|
|
|
// use c_str(), not XContainer::NSXString::ToCKSTRING because we want make sure this paramter is not nullptr.
|
|
|
|
// we always output a valid C style string, even if no chars need to write.
|
2023-08-23 16:04:58 +08:00
|
|
|
m_OutputCallback(result.c_str());
|
2023-02-26 21:48:03 +08:00
|
|
|
}
|
|
|
|
|
2023-08-23 16:04:58 +08:00
|
|
|
void CKContext::SetOutputCallback(OutputCallback cb) {
|
|
|
|
m_OutputCallback = cb;
|
2023-02-25 22:58:28 +08:00
|
|
|
}
|
|
|
|
|
2023-02-28 11:35:54 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
2023-08-23 16:04:58 +08:00
|
|
|
#pragma region Encoding utilities
|
2023-02-28 11:35:54 +08:00
|
|
|
|
2024-08-23 11:28:49 +08:00
|
|
|
void CKContext::GetUTF8String(const std::string& native_name, XContainer::XString& u8_name) {
|
|
|
|
bool conv_success = false, has_valid_token = false;
|
2023-03-04 11:11:36 +08:00
|
|
|
for (const auto& token : this->m_NameEncoding) {
|
2024-08-23 11:28:49 +08:00
|
|
|
if (token == EncodingHelper::INVALID_ENCODING_TOKEN) continue;
|
|
|
|
has_valid_token = true;
|
|
|
|
conv_success = EncodingHelper::ToUTF8(native_name, u8_name, token);
|
|
|
|
if (conv_success) break;
|
2023-03-04 11:11:36 +08:00
|
|
|
}
|
2024-08-23 11:28:49 +08:00
|
|
|
// fallback if failed.
|
|
|
|
if (!conv_success) {
|
|
|
|
if (!has_valid_token) {
|
|
|
|
throw RuntimeException("Try to get UTF8 string from ordinary string in CKContext but giving empty encoding candidate.");
|
|
|
|
} else {
|
|
|
|
u8_name.clear();
|
|
|
|
this->OutputToConsole(u8"Error when converting to UTF8 string from ordinary string. The string will leave to blank.");
|
|
|
|
}
|
2023-03-04 11:11:36 +08:00
|
|
|
}
|
2023-02-25 22:58:28 +08:00
|
|
|
}
|
|
|
|
|
2024-08-23 11:28:49 +08:00
|
|
|
void CKContext::GetOrdinaryString(const XContainer::XString& u8_name, std::string& native_name) {
|
|
|
|
bool conv_success = false, has_valid_token = false;
|
2023-03-04 11:11:36 +08:00
|
|
|
for (const auto& token : this->m_NameEncoding) {
|
2024-08-23 11:28:49 +08:00
|
|
|
if (token == EncodingHelper::INVALID_ENCODING_TOKEN) continue;
|
|
|
|
has_valid_token = true;
|
|
|
|
conv_success = EncodingHelper::ToOrdinary(u8_name, native_name, token);
|
|
|
|
if (conv_success) break;
|
2023-03-04 11:11:36 +08:00
|
|
|
}
|
2024-08-23 11:28:49 +08:00
|
|
|
// fallback if failed.
|
|
|
|
if (!conv_success) {
|
|
|
|
if (!has_valid_token) {
|
|
|
|
throw RuntimeException("Try to get ordinary string from UTF8 string in CKContext but giving empty encoding candidate.");
|
|
|
|
} else {
|
|
|
|
native_name.clear();
|
|
|
|
this->OutputToConsole(u8"Error when converting to ordinary string from UTF8 string. The string will leave to blank.");
|
|
|
|
}
|
2023-03-04 11:11:36 +08:00
|
|
|
}
|
2023-02-25 22:58:28 +08:00
|
|
|
}
|
|
|
|
|
2024-08-23 11:28:49 +08:00
|
|
|
void CKContext::SetEncoding(const XContainer::XArray<XContainer::XString>& encoding_seq) {
|
2023-03-04 11:11:36 +08:00
|
|
|
// free all current series
|
2024-08-23 11:28:49 +08:00
|
|
|
this->ClearEncoding();
|
2023-03-04 11:11:36 +08:00
|
|
|
// add new encoding
|
2024-08-23 11:28:49 +08:00
|
|
|
for (const auto& encoding_str : encoding_seq) {
|
|
|
|
this->m_NameEncoding.emplace_back(LibCmo::EncodingHelper::CreateEncodingToken(encoding_str));
|
2023-03-04 11:11:36 +08:00
|
|
|
}
|
2023-02-25 22:58:28 +08:00
|
|
|
}
|
|
|
|
|
2024-08-23 11:28:49 +08:00
|
|
|
void CKContext::ClearEncoding() {
|
|
|
|
for (const auto& token : this->m_NameEncoding) {
|
|
|
|
if (token == EncodingHelper::INVALID_ENCODING_TOKEN) continue;
|
|
|
|
LibCmo::EncodingHelper::DestroyEncodingToken(token);
|
|
|
|
}
|
|
|
|
this->m_NameEncoding.clear();
|
|
|
|
}
|
2023-02-25 22:58:28 +08:00
|
|
|
|
2024-08-23 11:28:49 +08:00
|
|
|
bool CKContext::IsValidEncoding() {
|
|
|
|
for (const auto& token : this->m_NameEncoding) {
|
|
|
|
if (token != EncodingHelper::INVALID_ENCODING_TOKEN) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2023-02-25 22:58:28 +08:00
|
|
|
|
2023-02-28 11:35:54 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
2023-02-25 22:58:28 +08:00
|
|
|
}
|