diff --git a/data/uking_functions.csv b/data/uking_functions.csv index fa88e913..275c8b0a 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -88713,8 +88713,8 @@ 0x0000007101166f44,ResourceBxml::parse,28,_ZThn632_N4ksys3res9ActorLink6parse_EPhmPN4sead4HeapE 0x0000007101166f60,sub_7101166F60,124,_ZN4ksys3res9ActorLink9finalize_Ev 0x0000007101166fdc,sub_7101166FDC,124,_ZThn632_N4ksys3res9ActorLink9finalize_Ev -0x0000007101167058,Bxml::hasTagByName,164,_ZNK4ksys3res9ActorLink6hasTagEPKc? -0x00000071011670fc,Bxml::hasTag,108,_ZNK4ksys3res9ActorLink6hasTagENS_3act3TagE +0x0000007101167058,Bxml::hasTagByName,164,_ZNK4ksys3res9ActorLink6hasTagEPKc +0x00000071011670fc,Bxml::hasTag,108,_ZNK4ksys3res9ActorLink6hasTagENS_3act3TagE? 0x0000007101167168,sub_7101167168,236,_ZN4ksys3res9ActorLinkD2Ev 0x0000007101167254,sub_7101167254,224,_ZN4ksys3res9ActorLinkD0Ev 0x0000007101167334,sub_7101167334,8,_ZNK4ksys3res9ActorLink27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE? @@ -90976,8 +90976,8 @@ 0x000000710120cbec,j__ZdlPv_1240,4, 0x000000710120cbf0,nullsub_4702,4, 0x000000710120cbf4,sub_710120CBF4,8, -0x000000710120cbfc,sub_710120CBFC,36, -0x000000710120cc20,sub_710120CC20,16, +0x000000710120cbfc,sub_710120CBFC,36,_ZN4ksys3res7CounterD0Ev? +0x000000710120cc20,sub_710120CC20,16,_ZN4ksys3res7Counter10doSetData_ERKNS0_11CounterBase4DataE 0x000000710120cc30,ResourceMgrInvoker::invoke,24, 0x000000710120cc48,ResourceMgrInvoker::clone,76, 0x000000710120cc94,ResourceMgrInvoker2::invoke,24, @@ -91058,9 +91058,9 @@ 0x0000007101213250,callResourceMgrTaskMethodOO,16, 0x0000007101213260,res::setCompactionStopped,24, 0x0000007101213278,res::texHandleMgrSetSomeFlags,24, -0x0000007101213290,return_1,8, -0x0000007101213298,return_0_,8, -0x00000071012132a0,return_0_2,8, +0x0000007101213290,return_1,8,_ZN4ksys3res18stubbedLogFunctionEv +0x0000007101213298,return_0_,8,_ZN4ksys3res11returnFalseEv +0x00000071012132a0,return_0_2,8,_ZN4ksys3res12returnFalse2Ev 0x00000071012132a8,nullsub_4703,4, 0x00000071012132ac,return_0__,8, 0x00000071012132b4,nullsub_4704,4, @@ -93226,30 +93226,30 @@ 0x00000071012bc86c,sub_71012BC86C,76, 0x00000071012bc8b8,nullsub_4787,4, 0x00000071012bc8bc,sub_71012BC8BC,76, -0x00000071012bc908,sub_71012BC908,32, -0x00000071012bc928,nullsub_4788,4, -0x00000071012bc92c,j__ZdlPv_1297,4, -0x00000071012bc930,sub_71012BC930,12, -0x00000071012bc93c,sub_71012BC93C,24, -0x00000071012bc954,sub_71012BC954,28, -0x00000071012bc970,sub_71012BC970,12, -0x00000071012bc97c,sub_71012BC97C,12, -0x00000071012bc988,sub_71012BC988,8, -0x00000071012bc990,ResourceInfoContainer::ctor,68, -0x00000071012bc9d4,ResourceInfoContainer::dtor,20, -0x00000071012bc9e8,ResourceInfoContainer::dtorDelete,52, -0x00000071012bca1c,ResourceInfoContainer::loadSizeTable,500, -0x00000071012bcc10,ResourceInfoContainer::getResourceSize,384, -0x00000071012bcd90,sub_71012BCD90,180, -0x00000071012bce44,sub_71012BCE44,176, -0x00000071012bcef4,res::ResourceMgrTask::BinderArray::ctor,136, -0x00000071012bcf7c,sub_71012BCF7C,80, -0x00000071012bcfcc,sub_71012BCFCC,96, -0x00000071012bd02c,res::ResourceMgrTask::BinderArray::setPointers,128, -0x00000071012bd0ac,res::ResourceMgrTask::BinderArray::getFreeBinder,116, -0x00000071012bd120,sub_71012BD120,116, -0x00000071012bd194,res::ResourceMgrTask::BinderArray::b,92, -0x00000071012bd1f0,res::ResourceMgrTask::BinderArray::a,92, +0x00000071012bc908,sub_71012BC908,32,_ZN4ksys3res11CounterBaseC2Ev +0x00000071012bc928,nullsub_4788,4,_ZN4ksys3res11CounterBaseD1Ev +0x00000071012bc92c,j__ZdlPv_1297,4,_ZN4ksys3res11CounterBaseD0Ev +0x00000071012bc930,sub_71012BC930,12,_ZN4ksys3res11CounterBase7setDataERKNS1_4DataE +0x00000071012bc93c,sub_71012BC93C,24,_ZN4ksys3res11CounterBase12incrementRefEv +0x00000071012bc954,sub_71012BC954,28,_ZN4ksys3res11CounterBase12decrementRefEv +0x00000071012bc970,sub_71012BC970,12,_ZN4ksys3res11CounterBase7setFlagEv +0x00000071012bc97c,sub_71012BC97C,12,_ZN4ksys3res11CounterBase5resetEv +0x00000071012bc988,sub_71012BC988,8,_ZNK4ksys3res11CounterBase9isFlagSetEv +0x00000071012bc990,ResourceInfoContainer::ctor,68,_ZN4ksys3res21ResourceInfoContainerC1Ev +0x00000071012bc9d4,ResourceInfoContainer::dtor,20,_ZN4ksys3res21ResourceInfoContainerD1Ev +0x00000071012bc9e8,ResourceInfoContainer::dtorDelete,52,_ZN4ksys3res21ResourceInfoContainerD0Ev +0x00000071012bca1c,ResourceInfoContainer::loadSizeTable,500,_ZN4ksys3res21ResourceInfoContainer21loadResourceSizeTableEv? +0x00000071012bcc10,ResourceInfoContainer::getResourceSize,384,_ZN4ksys3res21ResourceInfoContainer15getResourceSizeERKN4sead14SafeStringBaseIcEE? +0x00000071012bcd90,sub_71012BCD90,180,_ZNK4ksys3res21ResourceInfoContainer14ResStringEntry7compareERKN4sead14SafeStringBaseIcEE +0x00000071012bce44,sub_71012BCE44,176,_ZN4ksys3res12_GLOBAL__N_114stringLessThanERKN4sead14SafeStringBaseIcEES6_ +0x00000071012bcef4,res::ResourceMgrTask::BinderArray::ctor,136,_ZN4ksys3res16ResourceUnitPoolC1Ev +0x00000071012bcf7c,sub_71012BCF7C,80,_ZN4ksys3res16ResourceUnitPoolD1Ev +0x00000071012bcfcc,sub_71012BCFCC,96,_ZN4ksys3res16ResourceUnitPoolD0Ev +0x00000071012bd02c,res::ResourceMgrTask::BinderArray::setPointers,128,_ZN4ksys3res16ResourceUnitPool4initEv +0x00000071012bd0ac,res::ResourceMgrTask::BinderArray::getFreeBinder,116,_ZN4ksys3res16ResourceUnitPool8tryAllocEv +0x00000071012bd120,sub_71012BD120,116,_ZN4ksys3res16ResourceUnitPool5allocEv +0x00000071012bd194,res::ResourceMgrTask::BinderArray::b,92,_ZN4ksys3res16ResourceUnitPool4freeEPNS0_12ResourceUnitE +0x00000071012bd1f0,res::ResourceMgrTask::BinderArray::a,92,_ZN4ksys3res16ResourceUnitPool11freeForSyncEPNS0_12ResourceUnitE 0x00000071012bd24c,sub_71012BD24C,92, 0x00000071012bd2a8,sub_71012BD2A8,136, 0x00000071012bd330,sub_71012BD330,8, diff --git a/lib/sead b/lib/sead index 9b70917b..de2d5095 160000 --- a/lib/sead +++ b/lib/sead @@ -1 +1 @@ -Subproject commit 9b70917bc4c0b112ca38ba2a2df2c2f9624289b7 +Subproject commit de2d50951821f4b16e211a6f5042a3fe094e7b73 diff --git a/src/KingSystem/Resource/CMakeLists.txt b/src/KingSystem/Resource/CMakeLists.txt index 09ec38ef..bd9b5c16 100644 --- a/src/KingSystem/Resource/CMakeLists.txt +++ b/src/KingSystem/Resource/CMakeLists.txt @@ -88,12 +88,16 @@ target_sources(uking PRIVATE resCacheCriticalSection.h resControlTask.cpp resControlTask.h + resCounter.cpp + resCounter.h resCurrentResNameMgr.cpp resCurrentResNameMgr.h resEntryFactory.cpp resEntryFactory.h resHandle.cpp resHandle.h + resInfoContainer.cpp + resInfoContainer.h resLoadRequest.cpp resLoadRequest.h resMemoryTask.cpp @@ -102,11 +106,14 @@ target_sources(uking PRIVATE resOffsetReadFileDevice.h resResourceMgrTask.cpp resResourceMgrTask.h + resSystem.cpp resSystem.h resTaskRequest.cpp resTaskRequest.h resUnit.cpp resUnit.h + resUnitPool.cpp + resUnitPool.h resResource.cpp resResource.h diff --git a/src/KingSystem/Resource/resCounter.cpp b/src/KingSystem/Resource/resCounter.cpp new file mode 100644 index 00000000..20fc787a --- /dev/null +++ b/src/KingSystem/Resource/resCounter.cpp @@ -0,0 +1,40 @@ +#include "KingSystem/Resource/resCounter.h" + +namespace ksys::res { + +CounterBase::CounterBase() = default; + +CounterBase::~CounterBase() = default; + +bool CounterBase::setData(const CounterBase::Data& data) { + return doSetData_(data); +} + +void CounterBase::incrementRef() { + mRefCount.increment(); +} + +void CounterBase::decrementRef() { + if (mRefCount) + mRefCount.decrement(); +} + +void CounterBase::setFlag() { + mFlag = true; +} + +void CounterBase::reset() { + [[maybe_unused]] const auto count = mRefCount; + mFlag = false; +} + +bool CounterBase::isFlagSet() const { + return mFlag; +} + +bool Counter::doSetData_(const CounterBase::Data& data) { + mData = data.mData; + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/resCounter.h b/src/KingSystem/Resource/resCounter.h new file mode 100644 index 00000000..74b1913f --- /dev/null +++ b/src/KingSystem/Resource/resCounter.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class CounterBase { +public: + class DataBase { + SEAD_RTTI_BASE(DataBase) + }; + + class Data : public DataBase { + SEAD_RTTI_OVERRIDE(Data, DataBase) + public: + explicit Data(void* data) : mData(data) {} + virtual ~Data() = default; + void* mData; + }; + + CounterBase(); + virtual ~CounterBase(); + + bool setData(const Data& data); + + void incrementRef(); + void decrementRef(); + + void setFlag(); + void reset(); + bool isFlagSet() const; + +private: + virtual bool doSetData_(const Data& data) = 0; + + bool mFlag = true; + sead::Atomic mRefCount; +}; + +class Counter : public CounterBase { +public: + Counter() = default; + ~Counter() override = default; + +private: + bool doSetData_(const Data& data) override; + + void* mData = nullptr; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/resInfoContainer.cpp b/src/KingSystem/Resource/resInfoContainer.cpp new file mode 100644 index 00000000..f1669f80 --- /dev/null +++ b/src/KingSystem/Resource/resInfoContainer.cpp @@ -0,0 +1,113 @@ +#include "KingSystem/Resource/resInfoContainer.h" +#include +#include +#include "KingSystem/Resource/resLoadRequest.h" +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Resource/resSystem.h" + +namespace ksys::res { + +ResourceInfoContainer::ResourceInfoContainer() = default; + +ResourceInfoContainer::~ResourceInfoContainer() = default; + +// NON_MATCHING: LoadRequest field write order +bool ResourceInfoContainer::loadResourceSizeTable() { + const auto load_res = [&] { + LoadRequest req; + req._68 = nullptr; + req.mArena = nullptr; + req.mPackHandle = nullptr; + req._22 = false; + req._20 = false; + req._21 = false; + req._26 = false; + req.mFileDevice = nullptr; + req.mLoadCompressed = true; + req._24 = false; + req._8 = true; + req.mLoadDataAlignment = 8; + req.mBufferSize = 0; + req.mEntryFactory = nullptr; + req.mAocFileDevice = nullptr; + req._34 = 0; + req.mRequester = "ResourceInfoContainer"; + req.mPath = "System/Resource/ResourceSizeTable.product.rsizetable"; + req._c = 1; + return sead::DynamicCast(mRstbHandle.load(req.mPath, req)); + }; + + const Resource* resource = load_res(); + if (!resource) + return false; + + const u8* data = resource->getRawData(); + + if (data[0] == 'R' && data[1] == 'S' && data[2] == 'T' && data[3] == 'B') { + stubbedLogFunction(); + const auto num_entries = sead::BitUtil::bitCastPtr(data, 0x4); + const auto num_string_entries = sead::BitUtil::bitCastPtr(data, 0x8); + + auto* entries_data = + reinterpret_cast(reinterpret_cast(data) + 0xc); + + if (num_entries >= 1) { + mEntries = {num_entries, entries_data}; + entries_data += num_entries; + } + + if (num_string_entries >= 1) { + mStringEntries = {num_string_entries, + reinterpret_cast(entries_data)}; + // Log each conflict. + for (s32 i = 0; i < num_string_entries; ++i) + stubbedLogFunction(); + } + } else { + // Assume that there is no string table. + stubbedLogFunction(); + if (resource->getRawSize() != 0) { + const u32 num_entries = resource->getRawSize() / sizeof(ResEntry); + mEntries.setBuffer(num_entries, + reinterpret_cast(resource->getRawData())); + } + } + + stubbedLogFunction(); + stubbedLogFunction(); + stubbedLogFunction(); + return true; +} + +// NON_MATCHING: missing mStringEntries(string_entry_idx).res_size > 0 check +u32 ResourceInfoContainer::getResourceSize(const sead::SafeString& name) { + const u32 name_hash = sead::HashCRC32::calcStringHash(name.cstr()); + + const s32 entry_idx = mEntries.binarySearch({name_hash, 0}, ResEntry::compareT); + if (entry_idx >= 1 && mEntries(entry_idx).res_size > 0) + return mEntries(entry_idx).res_size; + + const s32 string_entry_idx = mStringEntries.binarySearchC( + [&](const ResStringEntry& entry) { return entry.compare(name); }); + if (string_entry_idx >= 1 && mStringEntries(string_entry_idx).res_size > 0) + return mStringEntries(string_entry_idx).res_size; + + return 0; +} + +namespace { +[[gnu::noinline]] bool stringLessThan(const sead::SafeString& a, const sead::SafeString& b) { + return a < b; +} +} // namespace + +[[gnu::noinline]] s32 +ResourceInfoContainer::ResStringEntry::compare(const sead::SafeString& name) const { + if (res_name > name) + return 1; + if (stringLessThan(res_name, name)) + return -1; + return 0; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/resInfoContainer.h b/src/KingSystem/Resource/resInfoContainer.h new file mode 100644 index 00000000..096e43fc --- /dev/null +++ b/src/KingSystem/Resource/resInfoContainer.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include "KingSystem/Resource/resHandle.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class ResourceInfoContainer { +public: + ResourceInfoContainer(); + virtual ~ResourceInfoContainer(); + + bool loadResourceSizeTable(); + u32 getResourceSize(const sead::SafeString& name); + +private: + struct ResEntry { + static s32 compareT(const ResEntry* lhs, const ResEntry* rhs) { + if (*lhs > *rhs) + return 1; + if (*lhs < *rhs) + return -1; + return 0; + } + + bool operator<(const ResEntry& other) const { return res_name_hash < other.res_name_hash; } + bool operator>(const ResEntry& other) const { return res_name_hash > other.res_name_hash; } + u32 res_name_hash; + s32 res_size; + }; + + struct ResStringEntry { + s32 compare(const sead::SafeString& name) const; + + char res_name[128]; + s32 res_size; + }; + + Handle mRstbHandle; + sead::Buffer mEntries; + sead::Buffer mStringEntries; +}; +KSYS_CHECK_SIZE_NX150(ResourceInfoContainer, 0x78); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/resResourceMgrTask.h b/src/KingSystem/Resource/resResourceMgrTask.h index 08051522..7a7524d9 100644 --- a/src/KingSystem/Resource/resResourceMgrTask.h +++ b/src/KingSystem/Resource/resResourceMgrTask.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include "KingSystem/Resource/resUnit.h" namespace sead { @@ -17,7 +19,7 @@ class TaskThread; namespace ksys::res { // FIXME: very, very incomplete. -class ResourceMgrTask { +class ResourceMgrTask : public sead::CalculateTask, public sead::hostio::Node { public: static ResourceMgrTask* instance() { return sInstance; } @@ -46,5 +48,7 @@ public: private: static ResourceMgrTask* sInstance; }; +KSYS_CHECK_SIZE_NX150(sead::TaskBase, 0xd0); +KSYS_CHECK_SIZE_NX150(sead::MethodTreeNode, 0x98); } // namespace ksys::res diff --git a/src/KingSystem/Resource/resSystem.cpp b/src/KingSystem/Resource/resSystem.cpp new file mode 100644 index 00000000..be87826c --- /dev/null +++ b/src/KingSystem/Resource/resSystem.cpp @@ -0,0 +1,17 @@ +#include "KingSystem/Resource/resSystem.h" + +namespace ksys::res { + +bool stubbedLogFunction() { + return true; +} + +bool returnFalse() { + return false; +} + +bool returnFalse2() { + return false; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/resSystem.h b/src/KingSystem/Resource/resSystem.h index 4c27f2b4..c22ac378 100644 --- a/src/KingSystem/Resource/resSystem.h +++ b/src/KingSystem/Resource/resSystem.h @@ -10,4 +10,8 @@ bool stubbedLogFunction(); // TODO: figure out what this is used for. Stubbed log function? bool returnFalse(); +// In release builds, the only thing this function does is return 0. +// TODO: figure out what this is used for. Stubbed log function? +bool returnFalse2(); + } // namespace ksys::res diff --git a/src/KingSystem/Resource/resUnitPool.cpp b/src/KingSystem/Resource/resUnitPool.cpp new file mode 100644 index 00000000..fd235159 --- /dev/null +++ b/src/KingSystem/Resource/resUnitPool.cpp @@ -0,0 +1,33 @@ +#include "KingSystem/Resource/resUnitPool.h" + +namespace ksys::res { + +ResourceUnitPool::ResourceUnitPool() = default; + +ResourceUnitPool::~ResourceUnitPool() = default; + +bool ResourceUnitPool::init() { + for (s32 i = 0; i < UnitCapacity; ++i) + mRingBuffer.pushBack(&mUnits[i]); + return true; +} + +ResourceUnit* ResourceUnitPool::tryAlloc() { + if (mRingBuffer.empty()) + return nullptr; + return mRingBuffer.popFront(); +} + +ResourceUnit* ResourceUnitPool::alloc() { + return mRingBuffer.popFront(); +} + +void ResourceUnitPool::free(ResourceUnit* unit) { + mRingBuffer.pushBack(unit); +} + +void ResourceUnitPool::freeForSync(ResourceUnit* unit) { + free(unit); +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/resUnitPool.h b/src/KingSystem/Resource/resUnitPool.h new file mode 100644 index 00000000..35e515ef --- /dev/null +++ b/src/KingSystem/Resource/resUnitPool.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include "KingSystem/Resource/resUnit.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class ResourceUnitPool { +public: + ResourceUnitPool(); + virtual ~ResourceUnitPool(); + + ResourceUnitPool(const ResourceUnitPool&) = delete; + ResourceUnitPool& operator=(const ResourceUnitPool&) = delete; + + bool init(); + + ResourceUnit* tryAlloc(); + ResourceUnit* alloc(); + + void free(ResourceUnit* unit); + void freeForSync(ResourceUnit* unit); + +private: + static constexpr s32 UnitCapacity = 9000; + + ResourceUnit mUnits[UnitCapacity]; + sead::FixedRingBuffer mRingBuffer; +}; +KSYS_CHECK_SIZE_NX150(ResourceUnitPool, 0x9c01a0); + +} // namespace ksys::res