diff --git a/data/uking_functions.csv b/data/uking_functions.csv index d372b65c..d1bd7227 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -74760,12 +74760,12 @@ 0x0000007100df67b8,sub_7100DF67B8,268, 0x0000007100df68c4,sub_7100DF68C4,268, 0x0000007100df69d0,sub_7100DF69D0,268, -0x0000007100df6adc,ResourceBgdata::ctor,136, -0x0000007100df6b64,ResourceBgdata::dtor,20, -0x0000007100df6b78,ResourceBgdata::dtorDelete,52, -0x0000007100df6bac,ResourceBgdata::doCreate,32556, -0x0000007100dfead8,GameDataFlag::DebugData::load,308, -0x0000007100dfec0c,GameDataFlag::Properties::ctor,256, +0x0000007100df6adc,ResourceBgdata::ctor,136,_ZN4ksys3res8GameDataC1Ev +0x0000007100df6b64,ResourceBgdata::dtor,20,_ZN4ksys3res8GameDataD1Ev +0x0000007100df6b78,ResourceBgdata::dtorDelete,52,_ZN4ksys3res8GameDataD0Ev +0x0000007100df6bac,ResourceBgdata::doCreate,32556,_ZN4ksys3res8GameData9doCreate_EPhjPN4sead4HeapE! +0x0000007100dfead8,GameDataFlag::DebugData::load,308,_ZN4ksys3res8GameData13loadDebugDataEPNS_3gdt13FlagDebugDataERKN2al9ByamlIterE +0x0000007100dfec0c,GameDataFlag::Properties::ctor,256,_ZN4ksys3res8GameData18loadFlagPropertiesEPNS_3gdt14FlagPropertiesERKN2al9ByamlIterE 0x0000007100dfed0c,GameDataFlagBool::m0,20,_ZN4ksys3gdt4FlagIbED2Ev 0x0000007100dfed20,GameDataFlagBool::m1,52,_ZN4ksys3gdt4FlagIbED0Ev 0x0000007100dfed54,GameDataFlagBool::getHash,8,_ZNK4ksys3gdt4FlagIbE7getHashEv diff --git a/lib/sead b/lib/sead index 03809dcc..5c347c3e 160000 --- a/lib/sead +++ b/lib/sead @@ -1 +1 @@ -Subproject commit 03809dcc60116923222b5e6ff066c14d6ba88da3 +Subproject commit 5c347c3ee762eba5595c107c448b527513dbb3e3 diff --git a/src/KingSystem/GameData/CMakeLists.txt b/src/KingSystem/GameData/CMakeLists.txt index 00246c49..fdff3c60 100644 --- a/src/KingSystem/GameData/CMakeLists.txt +++ b/src/KingSystem/GameData/CMakeLists.txt @@ -1,4 +1,6 @@ target_sources(uking PRIVATE gdtFlag.cpp gdtFlag.h + gdtManager.cpp + gdtManager.h ) diff --git a/src/KingSystem/GameData/gdtFlag.h b/src/KingSystem/GameData/gdtFlag.h index 8aceab40..d7e5f4bf 100644 --- a/src/KingSystem/GameData/gdtFlag.h +++ b/src/KingSystem/GameData/gdtFlag.h @@ -186,6 +186,7 @@ public: virtual bool setValue(T value); virtual FlagDebugData* getDebugData() const; + void setDebugData(FlagDebugData* data); private: sead::SizedEnum mType = FlagType::Invalid; @@ -381,4 +382,9 @@ inline FlagDebugData* Flag::getDebugData() const { return mDebugData; } +template +inline void Flag::setDebugData(FlagDebugData* data) { + mDebugData = data; +} + } // namespace ksys::gdt diff --git a/src/KingSystem/GameData/gdtManager.cpp b/src/KingSystem/GameData/gdtManager.cpp new file mode 100644 index 00000000..b483bef5 --- /dev/null +++ b/src/KingSystem/GameData/gdtManager.cpp @@ -0,0 +1,7 @@ +#include "KingSystem/GameData/gdtManager.h" + +namespace ksys::gdt { + +SEAD_SINGLETON_DISPOSER_IMPL(Manager) + +} diff --git a/src/KingSystem/GameData/gdtManager.h b/src/KingSystem/GameData/gdtManager.h new file mode 100644 index 00000000..b691eff3 --- /dev/null +++ b/src/KingSystem/GameData/gdtManager.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include "KingSystem/Resource/resHandle.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::gdt { + +class IManager { +public: + virtual ~IManager() = 0; +}; + +inline IManager::~IManager() = default; + +/// GameDataMgr communication. +class ManagerCom { +public: + virtual const char* getName() const { return "GameData"; } + virtual void syncData(); + + void* _8 = nullptr; + void* _10 = nullptr; +}; +KSYS_CHECK_SIZE_NX150(ManagerCom, 0x18); + +// FIXME: very incomplete. This is only here because res::GameData needs to use the Manager's heaps +class Manager : public IManager, public ManagerCom { + SEAD_SINGLETON_DISPOSER(Manager) + Manager(); + virtual ~Manager(); + +public: + sead::Heap* getGameDataHeap() const { return mGameDataHeap; } + sead::Heap* getSaveAreaHeap() const { return mSaveAreaHeap; } + sead::Heap* getGameDataComHeap() const { return mGameDataComHeap; } + +private: + sead::Heap* mGameDataHeap = nullptr; + sead::Heap* mSaveAreaHeap = nullptr; + sead::Heap* mGameDataComHeap = nullptr; + res::Handle mGameDataArcHandle; + sead::SafeArray mBgdataHandles; +}; +// FIXME: the size should be 0xDC8 +KSYS_CHECK_SIZE_NX150(Manager, 0xa58); + +} // namespace ksys::gdt diff --git a/src/KingSystem/Resource/CMakeLists.txt b/src/KingSystem/Resource/CMakeLists.txt index abf6860e..7d716fb5 100644 --- a/src/KingSystem/Resource/CMakeLists.txt +++ b/src/KingSystem/Resource/CMakeLists.txt @@ -132,6 +132,8 @@ target_sources(uking PRIVATE resResourceDemo.h resResourceDrop.cpp resResourceDrop.h + resResourceGameData.cpp + resResourceGameData.h resResourceGParamList.cpp resResourceGParamList.h resResourceLifeCondition.cpp diff --git a/src/KingSystem/Resource/resResourceGameData.cpp b/src/KingSystem/Resource/resResourceGameData.cpp new file mode 100644 index 00000000..7020a57d --- /dev/null +++ b/src/KingSystem/Resource/resResourceGameData.cpp @@ -0,0 +1,453 @@ +#include "KingSystem/Resource/resResourceGameData.h" +#include +#include "KingSystem/GameData/gdtManager.h" +#include "KingSystem/Utils/Byaml.h" +#include "KingSystem/Utils/HeapUtil.h" + +namespace ksys::res { + +GameData::GameData() = default; + +GameData::~GameData() { + ; +} + +namespace { +template +KSYS_ALWAYS_INLINE inline void +loadFlags(const sead::SafeString& data_type, const al::ByamlIter& root_iter, sead::Heap* heap, + sead::Buffer& flags, const sead::SafeString& wanted_data_type, + gdt::FlagType flag_type, const GetConfigFn& get_config_fn) { + constexpr bool IsBoolFlag = std::is_same(); + + if (data_type != wanted_data_type) + return; + + al::ByamlIter array_iter; + if (!root_iter.tryGetIterByIndex(&array_iter, 0)) + return; + + const auto num_flags = array_iter.getSize(); + if (num_flags > 0) + flags.allocBufferAssert(num_flags, heap); + + gdt::FlagProperties properties{}; + typename FlagType::ConfigType config{}; + + for (s32 i = 0; i < num_flags; ++i) { + al::ByamlIter iter; + if (!array_iter.tryGetIterByIndex(&iter, i)) + continue; + + gdt::FlagDebugData* debug_data = nullptr; + if (util::getDebugHeap()) + debug_data = new (util::getDebugHeap()) gdt::FlagDebugData(); + + GameData::loadDebugData(debug_data, iter); + + s32 hash = 0; + iter.tryGetIntByKey(&hash, "HashValue"); + const u32 hash_u = hash; + + GameData::loadFlagProperties(&properties, iter); + get_config_fn(&config, iter); + + flags[i].setDebugData(debug_data); + flags[i].setType(flag_type); + flags[i].setHash(hash_u); + flags[i].setConfig(config); + flags[i].resetToInitialValue(); + flags[i].setProperties(properties); + + if constexpr (IsBoolFlag) { + s32 category = 0; + iter.tryGetIntByKey(&category, "Category"); + flags[i].setCategory(category); + } + } +} + +template +KSYS_ALWAYS_INLINE inline void +loadArrayFlags(const sead::SafeString& data_type, const al::ByamlIter& root_iter, sead::Heap* heap, + sead::PtrArray>& flags, + const sead::SafeString& wanted_data_type, gdt::FlagType flag_type, + const GetConfigFn& get_config_fn, + const GetConfigForChildFlagFn& get_config_for_child_flag_fn) { + if (data_type != wanted_data_type) + return; + + al::ByamlIter array_iter; + if (!root_iter.tryGetIterByIndex(&array_iter, 0)) + return; + + const auto num_flags = array_iter.getSize(); + flags.allocBuffer(num_flags, heap); + + gdt::FlagProperties properties{}; + typename FlagType::ConfigType config{}; + + for (s32 i = 0; i < num_flags; ++i) { + al::ByamlIter iter; + if (!array_iter.tryGetIterByIndex(&iter, i)) + continue; + + gdt::FlagDebugData* debug_data = nullptr; + if (util::getDebugHeap()) + debug_data = new (util::getDebugHeap()) gdt::FlagDebugData(); + + GameData::loadDebugData(debug_data, iter); + + s32 hash = 0; + iter.tryGetIntByKey(&hash, "HashValue"); + const u32 hash_u = hash; + + GameData::loadFlagProperties(&properties, iter); + get_config_fn(&config, iter); + + al::ByamlIter values_iter; + al::ByamlIter init_value_iter; + if (iter.tryGetIterByKey(&init_value_iter, "InitValue")) { + al::ByamlIter item; + if (init_value_iter.tryGetIterByIndex(&item, 0)) + item.tryGetIterByKey(&values_iter, "Values"); + } + + const s32 num_items = values_iter.getSize(); + auto& buffer = *(new (heap) sead::Buffer); + buffer.allocBufferAssert(u32(num_items > 1 ? num_items : 1u), heap); + + for (s32 value_idx = 0; value_idx < num_items; ++value_idx) { + buffer[value_idx].setDebugData(debug_data); + buffer[value_idx].setType(flag_type); + buffer[value_idx].setHash(hash_u); + if (get_config_for_child_flag_fn(&config, values_iter, value_idx)) { + buffer[value_idx].setConfig(config); + buffer[value_idx].resetToInitialValue(); + } + buffer[value_idx].setProperties(properties); + } + + flags.pushBack(&buffer); + } +} + +inline void tryGetFloatOrInt(const al::ByamlIter& iter, const char* key, f32* value) { + if (iter.tryGetFloatByKey(value, key)) + return; + + s32 int_value{}; + iter.tryGetIntByKey(&int_value, key); + *value = int_value; +} + +inline void tryGetFloatOrIntByIndex(const al::ByamlIter& iter, s32 index, f32* value) { + if (iter.tryGetFloatByIndex(value, index)) + return; + + s32 int_value{}; + iter.tryGetIntByIndex(&int_value, index); + *value = int_value; +} + +template +KSYS_ALWAYS_INLINE inline bool tryGetVector(const al::ByamlIter& value_iter, T* vector) { + al::ByamlIter array_iter; + if (!value_iter.tryGetIterByIndex(&array_iter, 0)) + return false; + + for (size_t i = 0; i < vector->e.size(); ++i) + tryGetFloatOrIntByIndex(array_iter, i, &vector->e[i]); + + return true; +} +} // namespace + +// NON_MATCHING: +// * stack layout and reordering (possibly caused by the stack differences). +// * In init_string_array_flag_config, some calls to memcpy (for string copies) are replaced +// with memset and calcLength() is optimized out. +// * sead::Vector4::operator= (the original code does 64-bit loads and stores) +void GameData::doCreate_(u8* data, u32, sead::Heap*) { + auto* heap = gdt::Manager::instance()->getSaveAreaHeap(); + + const al::ByamlIter root_iter{data}; + + const char* key = nullptr; + root_iter.getKeyName(&key, 0); + const sead::SafeString data_type = key; + + loadFlags(data_type, root_iter, heap, mBoolFlags, "bool_data", gdt::FlagType::Bool, + [](gdt::FlagBool::ConfigType* config, const al::ByamlIter& iter) { + bool min_value{}; + bool max_value{}; + s32 init_value{}; + iter.tryGetIntByKey(&init_value, "InitValue"); + config->initial_value = init_value; + iter.tryGetBoolByKey(&min_value, "MinValue"); + iter.tryGetBoolByKey(&max_value, "MaxValue"); + }); + + loadFlags(data_type, root_iter, heap, mS32Flags, "s32_data", gdt::FlagType::S32, + [](gdt::FlagS32::ConfigType* config, const al::ByamlIter& iter) { + s32 init_value{}; + s32 min_value{}; + s32 max_value{}; + iter.tryGetIntByKey(&init_value, "InitValue"); + iter.tryGetIntByKey(&min_value, "MinValue"); + iter.tryGetIntByKey(&max_value, "MaxValue"); + config->initial_value = init_value; + config->min_value = min_value; + config->max_value = max_value; + }); + + loadFlags(data_type, root_iter, heap, mF32Flags, "f32_data", gdt::FlagType::F32, + [](gdt::FlagF32::ConfigType* config, const al::ByamlIter& iter) { + f32 init_value{}; + f32 min_value{}; + f32 max_value{}; + tryGetFloatOrInt(iter, "InitValue", &init_value); + tryGetFloatOrInt(iter, "MinValue", &min_value); + tryGetFloatOrInt(iter, "MaxValue", &max_value); + config->initial_value = init_value; + config->min_value = min_value; + config->max_value = max_value; + }); + + const auto init_string_flag_config = [](auto* config, const al::ByamlIter& iter) { + using StringType = decltype(config->initial_value); + + const char* init_value = ""; + iter.tryGetStringByKey(&init_value, "InitValue"); + + auto* debug_heap = util::getDebugHeap(); + if (debug_heap && !sead::SafeString(init_value).isEmpty()) { + auto* copy = new (debug_heap) StringType; + copy->copy(init_value); + init_value = copy->cstr(); + } + config->initial_value = StringType(init_value); + config->min_value = StringType(""); + config->max_value = StringType(""); + }; + + loadFlags(data_type, root_iter, heap, mStringFlags, "string_data", gdt::FlagType::String, + init_string_flag_config); + + loadFlags(data_type, root_iter, heap, mString64Flags, "string64_data", gdt::FlagType::String64, + init_string_flag_config); + + loadFlags(data_type, root_iter, heap, mString256Flags, "string256_data", + gdt::FlagType::String256, init_string_flag_config); + + const auto init_vector_flag_config = [](auto* config, const al::ByamlIter& iter) { + using VectorType = decltype(config->initial_value); + + VectorType init_value; + al::ByamlIter init_value_iter; + if (iter.tryGetIterByKey(&init_value_iter, "InitValue")) + tryGetVector(init_value_iter, &init_value); + + VectorType min_value; + al::ByamlIter min_value_iter; + if (iter.tryGetIterByKey(&min_value_iter, "MinValue")) + tryGetVector(min_value_iter, &min_value); + + VectorType max_value; + al::ByamlIter max_value_iter; + if (iter.tryGetIterByKey(&max_value_iter, "MaxValue")) + tryGetVector(max_value_iter, &max_value); + + config->initial_value = init_value; + config->min_value = min_value; + config->max_value = max_value; + }; + + loadFlags(data_type, root_iter, heap, mVector2fFlags, "vector2f_data", gdt::FlagType::Vector2f, + init_vector_flag_config); + + loadFlags(data_type, root_iter, heap, mVector3fFlags, "vector3f_data", gdt::FlagType::Vector3f, + init_vector_flag_config); + + loadFlags(data_type, root_iter, heap, mVector4fFlags, "vector4f_data", gdt::FlagType::Vector4f, + init_vector_flag_config); + + loadArrayFlags( + data_type, root_iter, heap, mBoolArrayFlags, "bool_array_data", gdt::FlagType::BoolArray, + [](gdt::FlagBool::ConfigType*, const al::ByamlIter& iter) { + bool min_value; + bool max_value; + iter.tryGetBoolByKey(&min_value, "MinValue"); + iter.tryGetBoolByKey(&max_value, "MaxValue"); + }, + [](gdt::FlagBool::ConfigType* config, const al::ByamlIter& values_iter, s32 value_idx) { + bool value; + s32 int_value{}; + if (values_iter.tryGetIntByIndex(&int_value, value_idx)) + value = int_value & 1; + else + values_iter.tryGetBoolByIndex(&value, value_idx); + config->initial_value = value; + return true; + }); + + loadArrayFlags( + data_type, root_iter, heap, mS32ArrayFlags, "s32_array_data", gdt::FlagType::S32Array, + [](gdt::FlagS32::ConfigType* config, const al::ByamlIter& iter) { + s32 min_value; + s32 max_value; + iter.tryGetIntByKey(&min_value, "MinValue"); + iter.tryGetIntByKey(&max_value, "MaxValue"); + config->min_value = min_value; + config->max_value = max_value; + }, + [](gdt::FlagS32::ConfigType* config, const al::ByamlIter& values_iter, s32 value_idx) { + s32 value; + values_iter.tryGetIntByIndex(&value, value_idx); + config->initial_value = value; + return true; + }); + + loadArrayFlags( + data_type, root_iter, heap, mF32ArrayFlags, "f32_array_data", gdt::FlagType::F32Array, + [](gdt::FlagF32::ConfigType* config, const al::ByamlIter& iter) { + f32 min_value; + f32 max_value; + iter.tryGetFloatByKey(&min_value, "MinValue"); + iter.tryGetFloatByKey(&max_value, "MaxValue"); + config->min_value = min_value; + config->max_value = max_value; + }, + [](gdt::FlagF32::ConfigType* config, const al::ByamlIter& values_iter, s32 value_idx) { + f32 value; + tryGetFloatOrIntByIndex(values_iter, value_idx, &value); + config->initial_value = value; + return true; + }); + + const auto init_string_array_flag_config = [](auto* config, const al::ByamlIter&) { + using StringType = decltype(config->initial_value); + config->min_value = StringType(""); + config->max_value = StringType(""); + }; + + const auto init_string_array_child_flag_config = + [heap](auto* config, const al::ByamlIter& values_iter, s32 value_idx) { + using StringType = decltype(config->initial_value); + + const char* init_value = ""; + values_iter.tryGetStringByIndex(&init_value, value_idx); + + if (!sead::SafeString(init_value).isEmpty()) { + auto* copy = new (heap) StringType; + copy->copy(init_value); + init_value = copy->cstr(); + } + config->initial_value = StringType(init_value); + return true; + }; + + loadArrayFlags(data_type, root_iter, heap, mStringArrayFlags, "string32_array_data", + gdt::FlagType::StringArray, init_string_array_flag_config, + init_string_array_child_flag_config); + + loadArrayFlags(data_type, root_iter, heap, mString64ArrayFlags, "string64_array_data", + gdt::FlagType::String64Array, init_string_array_flag_config, + init_string_array_child_flag_config); + + loadArrayFlags(data_type, root_iter, heap, mString256ArrayFlags, "string256_array_data", + gdt::FlagType::String256Array, init_string_array_flag_config, + init_string_array_child_flag_config); + + const auto init_vector_array_flag_config = [](auto* config, const al::ByamlIter& iter) { + using VectorType = decltype(config->initial_value); + + VectorType min_value; + al::ByamlIter min_value_iter; + if (iter.tryGetIterByKey(&min_value_iter, "MinValue")) + tryGetVector(min_value_iter, &min_value); + + VectorType max_value; + al::ByamlIter max_value_iter; + if (iter.tryGetIterByKey(&max_value_iter, "MaxValue")) + tryGetVector(max_value_iter, &max_value); + + config->min_value = min_value; + config->max_value = max_value; + }; + + const auto init_vector_array_child_flag_config = + [](auto* config, const al::ByamlIter& values_iter, s32 value_idx) { + using VectorType = decltype(config->initial_value); + + VectorType value; + al::ByamlIter value_iter; + if (!values_iter.tryGetIterByIndex(&value_iter, value_idx)) + return false; + + if (!tryGetVector(value_iter, &value)) + return false; + + config->initial_value = value; + return true; + }; + + loadArrayFlags(data_type, root_iter, heap, mVector2fArrayFlags, "vector2f_array_data", + gdt::FlagType::Vector2fArray, init_vector_array_flag_config, + init_vector_array_child_flag_config); + + loadArrayFlags(data_type, root_iter, heap, mVector3fArrayFlags, "vector3f_array_data", + gdt::FlagType::Vector3fArray, init_vector_array_flag_config, + init_vector_array_child_flag_config); + + loadArrayFlags(data_type, root_iter, heap, mVector4fArrayFlags, "vector4f_array_data", + gdt::FlagType::Vector4fArray, init_vector_array_flag_config, + init_vector_array_child_flag_config); +} + +void GameData::loadDebugData(gdt::FlagDebugData* data, const al::ByamlIter& iter) { + if (!data) + return; + + const char* data_name = ""; + s32 delete_rev = -1; + + iter.tryGetStringByKey(&data_name, "DataName"); + iter.tryGetIntByKey(&delete_rev, "DeleteRev"); + + data->name = ""; + if (util::getDebugHeap() && !sead::SafeString(data_name).isEmpty()) { + const s32 len = sead::SafeString(data_name).calcLength(); + auto* ptr = new (util::getDebugHeap()) char[len + 1]; + std::strncpy(ptr, data_name, len); + ptr[len] = sead::SafeString::cNullChar; + data->name = ptr; + } + + data->delete_rev = delete_rev; +} + +void GameData::loadFlagProperties(gdt::FlagProperties* properties, const al::ByamlIter& iter) { + bool is_one_trigger = false; + bool is_program_readable = false; + bool is_program_writable = false; + bool is_save = false; + bool is_event_associated = false; + int reset_type = 0; + + iter.tryGetBoolByKey(&is_one_trigger, "IsOneTrigger"); + iter.tryGetBoolByKey(&is_program_readable, "IsProgramReadable"); + iter.tryGetBoolByKey(&is_program_writable, "IsProgramWritable"); + iter.tryGetBoolByKey(&is_save, "IsSave"); + iter.tryGetBoolByKey(&is_event_associated, "IsEventAssociated"); + iter.tryGetIntByKey(&reset_type, "ResetType"); + + properties->setIsOneTrigger(is_one_trigger); + properties->setIsProgramReadable(is_program_readable); + properties->setIsProgramWritable(is_program_writable); + properties->setIsSave(is_save); + properties->setIsEventAssociated(is_event_associated); + properties->setResetType(gdt::ResetType(reset_type)); +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/resResourceGameData.h b/src/KingSystem/Resource/resResourceGameData.h new file mode 100644 index 00000000..da8beeeb --- /dev/null +++ b/src/KingSystem/Resource/resResourceGameData.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include "KingSystem/GameData/gdtFlag.h" +#include "KingSystem/Utils/Types.h" + +namespace al { +class ByamlIter; +} + +namespace ksys::res { + +class GameData : public sead::DirectResource { +public: + static void loadDebugData(gdt::FlagDebugData* data, const al::ByamlIter& iter); + static void loadFlagProperties(gdt::FlagProperties* properties, const al::ByamlIter& iter); + + GameData(); + ~GameData() override; + void doCreate_(u8* buffer, u32 values_iter, sead::Heap* heap) override; + + s32 getField14() const { return _14; } + + const sead::Buffer& getBoolFlags() const { return mBoolFlags; } + const sead::Buffer& getS32Flags() const { return mS32Flags; } + const sead::Buffer& getF32Flags() const { return mF32Flags; } + const sead::Buffer& getStringFlags() const { return mStringFlags; } + const sead::Buffer& getString64Flags() const { return mString64Flags; } + const sead::Buffer& getString256Flags() const { return mString256Flags; } + const sead::Buffer& getVector2fFlags() const { return mVector2fFlags; } + const sead::Buffer& getVector3fFlags() const { return mVector3fFlags; } + const sead::Buffer& getVector4fFlags() const { return mVector4fFlags; } + const sead::PtrArray& getBoolArrayFlags() const { return mBoolArrayFlags; } + const sead::PtrArray& getS32ArrayFlags() const { return mS32ArrayFlags; } + const sead::PtrArray& getF32ArrayFlags() const { return mF32ArrayFlags; } + + const sead::PtrArray& getStringArrayFlags() const { + return mStringArrayFlags; + } + const sead::PtrArray& getString64ArrayFlags() const { + return mString64ArrayFlags; + } + const sead::PtrArray& getString256ArrayFlags() const { + return mString256ArrayFlags; + } + const sead::PtrArray& getVector2fArrayFlags() const { + return mVector2fArrayFlags; + } + const sead::PtrArray& getVector3fArrayFlags() const { + return mVector3fArrayFlags; + } + const sead::PtrArray& getVector4fArrayFlags() const { + return mVector4fArrayFlags; + } + +private: + s32 _14 = -1; + + sead::Buffer mBoolFlags; + sead::Buffer mS32Flags; + sead::Buffer mF32Flags; + sead::Buffer mStringFlags; + sead::Buffer mString64Flags; + sead::Buffer mString256Flags; + sead::Buffer mVector2fFlags; + sead::Buffer mVector3fFlags; + sead::Buffer mVector4fFlags; + + sead::PtrArray mBoolArrayFlags; + sead::PtrArray mS32ArrayFlags; + sead::PtrArray mF32ArrayFlags; + sead::PtrArray mStringArrayFlags; + sead::PtrArray mString64ArrayFlags; + sead::PtrArray mString256ArrayFlags; + sead::PtrArray mVector2fArrayFlags; + sead::PtrArray mVector3fArrayFlags; + sead::PtrArray mVector4fArrayFlags; +}; +KSYS_CHECK_SIZE_NX150(GameData, 0x140); + +} // namespace ksys::res