From c00028c2144d93e7a35121b7efb4ab37b2af89f0 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Mon, 13 Feb 2023 23:21:25 -0600 Subject: [PATCH] feat(db): load achievement db --- src/CMakeLists.txt | 1 + src/client/CMakeLists.txt | 1 + src/client/Client.cpp | 5 +- src/db/CMakeLists.txt | 16 ++++ src/db/Db.cpp | 20 +++++ src/db/Db.hpp | 11 +++ src/db/IDatabase.hpp | 15 ++++ src/db/WowClientDB.hpp | 157 ++++++++++++++++++++++++++++++++++ src/db/WowClientDB_Base.hpp | 22 +++++ src/db/WowClientDB_Common.hpp | 11 +++ src/db/rec/AchievementRec.cpp | 94 ++++++++++++++++++++ src/db/rec/AchievementRec.hpp | 32 +++++++ 12 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 src/db/CMakeLists.txt create mode 100644 src/db/Db.cpp create mode 100644 src/db/Db.hpp create mode 100644 src/db/IDatabase.hpp create mode 100644 src/db/WowClientDB.hpp create mode 100644 src/db/WowClientDB_Base.hpp create mode 100644 src/db/WowClientDB_Common.hpp create mode 100644 src/db/rec/AchievementRec.cpp create mode 100644 src/db/rec/AchievementRec.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f47fd48..d6f8e6e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(app) add_subdirectory(async) add_subdirectory(client) +add_subdirectory(db) add_subdirectory(event) add_subdirectory(glue) add_subdirectory(gx) diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 1bace55..5b677d4 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -12,6 +12,7 @@ target_include_directories(client target_link_libraries(client PRIVATE async + db event gx model diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 5104105..b23d7b3 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -1,6 +1,7 @@ #include "client/Client.hpp" #include "client/ClientServices.hpp" #include "client/Console.hpp" +#include "db/Db.hpp" #include "async/AsyncFile.hpp" #include "glue/CGlueMgr.hpp" #include "gx/Device.hpp" @@ -353,7 +354,9 @@ void WowClientInit() { ClientMiscInitialize(); // sub_401B60(); - // ClientDBInitialize(); + + ClientDBInitialize(); + // LoadingScreenInitialize(); FrameScript_Initialize(0); diff --git a/src/db/CMakeLists.txt b/src/db/CMakeLists.txt new file mode 100644 index 0000000..7c61184 --- /dev/null +++ b/src/db/CMakeLists.txt @@ -0,0 +1,16 @@ +file(GLOB PRIVATE_SOURCES "*.cpp" "rec/*.cpp") + +add_library(db STATIC + ${PRIVATE_SOURCES} +) + +target_include_directories(db + PRIVATE + ${CMAKE_SOURCE_DIR}/src +) + +target_link_libraries(db + PUBLIC + common + storm +) diff --git a/src/db/Db.cpp b/src/db/Db.cpp new file mode 100644 index 0000000..3454533 --- /dev/null +++ b/src/db/Db.cpp @@ -0,0 +1,20 @@ +#include "db/Db.hpp" +#include "db/WowClientDB_Base.hpp" + +WowClientDB g_achievementDB; + +void LoadDB(WowClientDB_Base* db, const char* filename, int32_t linenumber) { + db->Load(filename, linenumber); +}; + +void StaticDBLoadAll(void (*loadFn)(WowClientDB_Base*, const char*, int32_t)) { + loadFn(&g_achievementDB, __FILE__, __LINE__); +}; + +void ClientDBInitialize() { + // TODO + + StaticDBLoadAll(LoadDB); + + // TODO +} diff --git a/src/db/Db.hpp b/src/db/Db.hpp new file mode 100644 index 0000000..3dbc2fb --- /dev/null +++ b/src/db/Db.hpp @@ -0,0 +1,11 @@ +#ifndef DB_DB_HPP +#define DB_DB_HPP + +#include "db/rec/AchievementRec.hpp" +#include "db/WowClientDB.hpp" + +extern WowClientDB g_achievementDB; + +void ClientDBInitialize(); + +#endif diff --git a/src/db/IDatabase.hpp b/src/db/IDatabase.hpp new file mode 100644 index 0000000..1fb4b3a --- /dev/null +++ b/src/db/IDatabase.hpp @@ -0,0 +1,15 @@ +#ifndef DB_I_DATABASE_HPP +#define DB_I_DATABASE_HPP + +template +class IDatabase { + public: + // Member variables + T* m_records = nullptr; + T** m_recordsById = nullptr; + + // Virtual member functions + virtual T* GetRecord(int32_t id) = 0; +}; + +#endif diff --git a/src/db/WowClientDB.hpp b/src/db/WowClientDB.hpp new file mode 100644 index 0000000..f98c206 --- /dev/null +++ b/src/db/WowClientDB.hpp @@ -0,0 +1,157 @@ +#ifndef DB_WOW_CLIENT_DB_HPP +#define DB_WOW_CLIENT_DB_HPP + +#include "db/IDatabase.hpp" +#include "db/WowClientDB_Common.hpp" +#include +#include +#include + +template +class WowClientDB : public WowClientDB_Common, IDatabase { + public: + // Virtual member functions + virtual void Load(const char* filename, int32_t linenumber); + virtual void LoadRecords(SFile* f, const char* filename, int32_t linenumber); + virtual int32_t GetRecordByIndex(int32_t index, void* ptr) const; + virtual T* GetRecord(int32_t id); +}; + +template +int32_t WowClientDB::GetRecordByIndex(int32_t index, void* ptr) const { + STORM_ASSERT(this->m_numRecords >= 0); + + if (index < 0 || index >= this->m_numRecords) { + return 0; + } + + memcpy(ptr, &this->m_records[index], sizeof(T)); + + return 1; +} + +template +T* WowClientDB::GetRecord(int32_t id) { + STORM_ASSERT(this->m_numRecords >= 0); + + if (id < this->m_minID || id > this->m_maxID) { + return nullptr; + } + + return this->m_recordsById[id - this->m_minID]; +} + +template +void WowClientDB::Load(const char* filename, int32_t linenumber) { + if (this->m_loaded) { + // TODO + // SErrDisplayAppFatalCustom(0x85100079, "%s already loaded! Aborting to prevent memory leak!", T::GetFilename()); + return; + } + + SFile* f; + if (!SFile::OpenEx(nullptr, T::GetFilename(), 0x20000, &f)) { + // TODO + // SErrDisplayAppFatalCustom(0x85100079, "Unable to open %s", T::GetFilename()); + return; + } + + uint32_t signature; + if (!SFile::Read(f, &signature, sizeof(signature), nullptr, nullptr, nullptr)) { + // TODO + // SErrDisplayAppFatalCustom(0x85100079, "Unable to read signature from %s", T::GetFilename()); + return; + } + + if (signature != 'CBDW') { + // TODO + // SErrDisplayAppFatalCustom(0x85100079, "Invalid signature 0x%x from %s", signature, T::GetFilename()); + return; + } + + if (!SFile::Read(f, &this->m_numRecords, sizeof(this->m_numRecords), nullptr, nullptr, nullptr)) { + // TODO + // SErrDisplayAppFatalCustom(0x85100079, "Unable to read record count from %s", T::GetFilename()); + return; + } + + if (!this->m_numRecords) { + SFile::Close(f); + return; + } + + uint32_t columnCount; + if (!SFile::Read(f, &columnCount, sizeof(columnCount), nullptr, nullptr, nullptr)) { + // TODO + // SErrDisplayAppFatalCustom(0x85100079, "Unable to read column count from %s", T::GetFilename()); + return; + } + + if (columnCount != T::columnCount) { + // TODO + // SErrDisplayAppFatalCustom(0x85100079, "%s has wrong number of columns (found %i, expected %i)", T::GetFilename(), columnCount, T::columnCount); + return; + } + + uint32_t rowSize; + if (!SFile::Read(f, &rowSize, sizeof(rowSize), nullptr, nullptr, nullptr)) { + // TODO + // SErrDisplayAppFatalCustom(0x85100079, "Unable to read row size from %s", T::GetFilename()); + return; + } + + if (rowSize != T::rowSize) { + // TODO + // SErrDisplayAppFatalCustom(0x85100079, "%s has wrong row size (found %i, expected %i)", T::GetFilename(), rowSize, T::rowSize); + return; + } + + uint32_t stringSize; + if (!SFile::Read(f, &stringSize, sizeof(stringSize), nullptr, nullptr, nullptr)) { + // TODO + // SErrDisplayAppFatalCustom(0x85100079, "Unable to read string size from %s", T::GetFilename()); + return; + } + + auto stringBuffer = SMemAlloc(stringSize, filename, linenumber, 0x0); + this->m_strings = static_cast(stringBuffer); + + this->m_maxID = 0; + this->m_minID = 0xFFFFFFF; + + this->LoadRecords(f, filename, linenumber); + + if (!SFile::Read(f, const_cast(this->m_strings), stringSize, nullptr, nullptr, nullptr)) { + SErrDisplayAppFatal("%s: Cannot read string table", T::GetFilename()); + } + + SFile::Close(f); + + this->m_loaded = 1; +} + +template +void WowClientDB::LoadRecords(SFile* f, const char* filename, int32_t linenumber) { + auto records = SMemAlloc(sizeof(T) * this->m_numRecords, filename, linenumber, 0x0); + this->m_records = static_cast(records); + + for (uint32_t i = 0; i < this->m_numRecords; i++) { + auto record = &this->m_records[i]; + record->Read(f, this->m_strings); + + this->m_maxID = record->m_ID > this->m_maxID ? record->m_ID : this->m_maxID; + this->m_minID = record->m_ID < this->m_minID ? record->m_ID : this->m_minID; + } + + auto recordsById = SMemAlloc(sizeof(void*) * (this->m_maxID - this->m_minID + 1), __FILE__, __LINE__, 0x0); + memset(recordsById, 0, sizeof(void*) * (this->m_maxID - this->m_minID + 1)); + this->m_recordsById = static_cast(recordsById); + + for (uint32_t i = 0; i < this->m_numRecords; i++) { + auto record = &this->m_records[i]; + auto id = record->m_ID - this->m_minID; + this->m_recordsById[id] = record; + } +} + +#endif diff --git a/src/db/WowClientDB_Base.hpp b/src/db/WowClientDB_Base.hpp new file mode 100644 index 0000000..910f4a2 --- /dev/null +++ b/src/db/WowClientDB_Base.hpp @@ -0,0 +1,22 @@ +#ifndef DB_WOW_CLIENT_DB_BASE_HPP +#define DB_WOW_CLIENT_DB_BASE_HPP + +#include "util/SFile.hpp" +#include + +class WowClientDB_Base { + public: + // Member variables + int32_t m_loaded = 0; + int32_t m_numRecords = 0; + int32_t m_maxID = -1; + int32_t m_minID = 0xFFFFFFF; + const char* m_strings = nullptr; + + // Virtual member functions + virtual void Load(const char* filename, int32_t linenumber) = 0; + virtual void LoadRecords(SFile* f, const char* filename, int32_t linenumber) = 0; + virtual int32_t GetRecordByIndex(int32_t index, void* ptr) const = 0; +}; + +#endif diff --git a/src/db/WowClientDB_Common.hpp b/src/db/WowClientDB_Common.hpp new file mode 100644 index 0000000..2fd39f0 --- /dev/null +++ b/src/db/WowClientDB_Common.hpp @@ -0,0 +1,11 @@ +#ifndef DB_WOW_CLIENT_DB_COMMON_HPP +#define DB_WOW_CLIENT_DB_COMMON_HPP + +#include "db/WowClientDB_Base.hpp" + +template +class WowClientDB_Common : public WowClientDB_Base { + public: +}; + +#endif diff --git a/src/db/rec/AchievementRec.cpp b/src/db/rec/AchievementRec.cpp new file mode 100644 index 0000000..854b629 --- /dev/null +++ b/src/db/rec/AchievementRec.cpp @@ -0,0 +1,94 @@ +#include "db/rec/AchievementRec.hpp" +#include "util/SFile.hpp" + +const char* AchievementRec::GetFilename() { + return "DBFilesClient\\Achievement.dbc"; +} + +bool AchievementRec::Read(SFile* f, const char* stringBuffer) { + uint32_t titleOfs[16]; + uint32_t titleMask; + uint32_t descriptionOfs[16]; + uint32_t descriptionMask; + uint32_t rewardOfs[16]; + uint32_t rewardMask; + + if ( + !SFile::Read(f, &this->m_ID, sizeof(this->m_ID), nullptr, nullptr, nullptr) + || !SFile::Read(f, &this->m_faction, sizeof(this->m_faction), nullptr, nullptr, nullptr) + || !SFile::Read(f, &this->m_instanceID, sizeof(this->m_instanceID), nullptr, nullptr, nullptr) + || !SFile::Read(f, &this->m_supercedes, sizeof(this->m_supercedes), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[0], sizeof(titleOfs[0]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[1], sizeof(titleOfs[1]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[2], sizeof(titleOfs[2]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[3], sizeof(titleOfs[3]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[4], sizeof(titleOfs[4]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[5], sizeof(titleOfs[5]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[6], sizeof(titleOfs[6]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[7], sizeof(titleOfs[7]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[8], sizeof(titleOfs[8]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[9], sizeof(titleOfs[9]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[10], sizeof(titleOfs[10]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[11], sizeof(titleOfs[11]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[12], sizeof(titleOfs[12]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[13], sizeof(titleOfs[13]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[14], sizeof(titleOfs[14]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleOfs[15], sizeof(titleOfs[15]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &titleMask, sizeof(titleMask), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[0], sizeof(descriptionOfs[0]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[1], sizeof(descriptionOfs[1]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[2], sizeof(descriptionOfs[2]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[3], sizeof(descriptionOfs[3]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[4], sizeof(descriptionOfs[4]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[5], sizeof(descriptionOfs[5]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[6], sizeof(descriptionOfs[6]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[7], sizeof(descriptionOfs[7]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[8], sizeof(descriptionOfs[8]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[9], sizeof(descriptionOfs[9]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[10], sizeof(descriptionOfs[10]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[11], sizeof(descriptionOfs[11]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[12], sizeof(descriptionOfs[12]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[13], sizeof(descriptionOfs[13]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[14], sizeof(descriptionOfs[14]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionOfs[15], sizeof(descriptionOfs[15]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &descriptionMask, sizeof(descriptionMask), nullptr, nullptr, nullptr) + || !SFile::Read(f, &this->m_category, sizeof(this->m_category), nullptr, nullptr, nullptr) + || !SFile::Read(f, &this->m_points, sizeof(this->m_points), nullptr, nullptr, nullptr) + || !SFile::Read(f, &this->m_uiOrder, sizeof(this->m_uiOrder), nullptr, nullptr, nullptr) + || !SFile::Read(f, &this->m_flags, sizeof(this->m_flags), nullptr, nullptr, nullptr) + || !SFile::Read(f, &this->m_iconID, sizeof(this->m_iconID), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[0], sizeof(rewardOfs[0]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[1], sizeof(rewardOfs[1]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[2], sizeof(rewardOfs[2]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[3], sizeof(rewardOfs[3]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[4], sizeof(rewardOfs[4]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[5], sizeof(rewardOfs[5]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[6], sizeof(rewardOfs[6]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[7], sizeof(rewardOfs[7]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[8], sizeof(rewardOfs[8]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[9], sizeof(rewardOfs[9]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[10], sizeof(rewardOfs[10]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[11], sizeof(rewardOfs[11]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[12], sizeof(rewardOfs[12]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[13], sizeof(rewardOfs[13]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[14], sizeof(rewardOfs[14]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardOfs[15], sizeof(rewardOfs[15]), nullptr, nullptr, nullptr) + || !SFile::Read(f, &rewardMask, sizeof(rewardMask), nullptr, nullptr, nullptr) + || !SFile::Read(f, &this->m_minimumCriteria, sizeof(this->m_minimumCriteria), nullptr, nullptr, nullptr) + || !SFile::Read(f, &this->m_sharesCriteria, sizeof(this->m_sharesCriteria), nullptr, nullptr, nullptr) + ) { + return false; + } + + if (stringBuffer) { + this->m_title = &stringBuffer[titleOfs[0]]; + this->m_description = &stringBuffer[descriptionOfs[0]]; + this->m_reward = &stringBuffer[rewardOfs[0]]; + } else { + this->m_title = ""; + this->m_description = ""; + this->m_reward = ""; + } + + return true; +} diff --git a/src/db/rec/AchievementRec.hpp b/src/db/rec/AchievementRec.hpp new file mode 100644 index 0000000..b6ff423 --- /dev/null +++ b/src/db/rec/AchievementRec.hpp @@ -0,0 +1,32 @@ +#ifndef DB_REC_ACHIEVEMENT_REC_HPP +#define DB_REC_ACHIEVEMENT_REC_HPP + +#include + +class SFile; + +class AchievementRec { + public: + static constexpr uint32_t columnCount = 62; + static constexpr uint32_t rowSize = 248; + + int32_t m_ID; + int32_t m_faction; + int32_t m_instanceID; + int32_t m_supercedes; + const char* m_title; + const char* m_description; + int32_t m_category; + int32_t m_points; + int32_t m_uiOrder; + int32_t m_flags; + uint32_t m_iconID; + const char* m_reward; + int32_t m_minimumCriteria; + int32_t m_sharesCriteria; + + static const char* GetFilename(); + bool Read(SFile* f, const char* stringBuffer); +}; + +#endif