diff options
| author | Léo Lam <leo@leolam.fr> | 2020-10-13 02:11:12 +0200 |
|---|---|---|
| committer | Léo Lam <leo@leolam.fr> | 2020-10-15 17:09:26 +0200 |
| commit | b16ba552db85d87409a610ab39fbde6670f73bde (patch) | |
| tree | db89213555787f250df86b730c6c34c11b04bbff /src/KingSystem/Resource | |
| parent | 436085f61dc25a387b2c0eae0380eaf1e1aa6e12 (diff) | |
ksys/res: Implement all of Handle
Diffstat (limited to 'src/KingSystem/Resource')
| -rw-r--r-- | src/KingSystem/Resource/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/KingSystem/Resource/resHandle.cpp | 416 | ||||
| -rw-r--r-- | src/KingSystem/Resource/resHandle.h | 37 | ||||
| -rw-r--r-- | src/KingSystem/Resource/resInfoContainer.cpp | 2 | ||||
| -rw-r--r-- | src/KingSystem/Resource/resLoadRequest.cpp | 20 | ||||
| -rw-r--r-- | src/KingSystem/Resource/resResourceMgrTask.h | 10 | ||||
| -rw-r--r-- | src/KingSystem/Resource/resUnit.cpp | 30 | ||||
| -rw-r--r-- | src/KingSystem/Resource/resUnit.h | 21 |
8 files changed, 482 insertions, 55 deletions
diff --git a/src/KingSystem/Resource/CMakeLists.txt b/src/KingSystem/Resource/CMakeLists.txt index 068e3f13..abf6860e 100644 --- a/src/KingSystem/Resource/CMakeLists.txt +++ b/src/KingSystem/Resource/CMakeLists.txt @@ -100,7 +100,6 @@ target_sources(uking PRIVATE resHandle.h resInfoContainer.cpp resInfoContainer.h - resLoadRequest.cpp resLoadRequest.h resMemoryTask.cpp resMemoryTask.h diff --git a/src/KingSystem/Resource/resHandle.cpp b/src/KingSystem/Resource/resHandle.cpp index 1655a485..81e43aa2 100644 --- a/src/KingSystem/Resource/resHandle.cpp +++ b/src/KingSystem/Resource/resHandle.cpp @@ -2,8 +2,11 @@ #include <container/seadBuffer.h> #include <prim/seadSafeString.h> #include <time/seadTickTime.h> +#include "KingSystem/Resource/resLoadRequest.h" +#include "KingSystem/Resource/resResource.h" #include "KingSystem/Resource/resResourceMgrTask.h" #include "KingSystem/Resource/resSystem.h" +#include "KingSystem/Utils/Debug.h" namespace ksys::res { @@ -40,13 +43,28 @@ const sead::SafeString sStatusStrings_[0x11] = { }; const sead::Buffer<const sead::SafeString> sStatusStrings{0x11, sStatusStrings_}; +ILoadRequest::~ILoadRequest() { + ; +} + +LoadRequest::LoadRequest() = default; + +LoadRequest::LoadRequest(s32 load_data_alignment, u32 arg_c, bool arg_20) + : _20(arg_20), mLoadDataAlignment(load_data_alignment) { + _c = arg_c; +} + +SimpleLoadRequest::SimpleLoadRequest() = default; + +SimplePackedLoadRequest::SimplePackedLoadRequest() = default; + Handle::Handle() = default; Handle::~Handle() { - unload(); + requestUnload(); } -void Handle::unload() { +void Handle::requestUnload() { if (!mFlags.isOn(Flag::_2)) return; @@ -69,4 +87,398 @@ void Handle::unload() { ResourceMgrTask::instance()->requestUnload(this); } +sead::DirectResource* Handle::getResource() const { + if (!isSuccess()) + return nullptr; + return mUnit->mResource; +} + +bool Handle::isSuccess() const { + if (mFlags.isOff(Flag::_2)) + return false; + + if (isBusy()) + return false; + + if (!mUnit || !mUnit->isParseOk()) + return false; + + return true; +} + +sead::DirectResource* Handle::getResourceUnchecked() const { + return mUnit->mResource; +} + +Handle::Status Handle::getStatus() const { + return mStatus; +} + +void Handle::setStatusForResourceMgr_(const Status& status) { + mStatus = status; +} + +inline bool Handle::checkPathChange_(const sead::SafeString& path) { + if (!mFlags.isOn(Flag::_2)) + return true; + + stubbedLogFunction(); + sead::FormatFixedSafeString<512> message("↓↓↓\n前回ファイル:%s\n今回ファイル:%s\n↑↑↑\n", + mUnit ? mUnit->mPath.cstr() : "***", path.cstr()); + util::PrintDebug(message); + return false; +} + +sead::DirectResource* Handle::load(const sead::SafeString& path, const ILoadRequest* request, + Handle::Status* out_status) { + if (checkPathChange_(path)) { + mFlags.reset(Flag::_F); + mFlags.set(Flag::_2); + mStatus = Status::_0; + if (request) { + ResourceMgrTask::instance()->requestLoadForSync(this, path, *request); + } else { + LoadRequest temp_request; + ResourceMgrTask::instance()->requestLoadForSync(this, path, temp_request); + } + if (out_status) + *out_status = mStatus; + } else { + if (out_status) + *out_status = Status::_8; + } + + return getResource(); +} + +bool Handle::isFlag2Set() const { + return mFlags.isOn(Flag::_2); +} + +bool Handle::requestLoad(const sead::SafeString& path, const ILoadRequest* request, + Handle::Status* out_status) { + if (checkPathChange_(path)) { + mFlags.reset(Flag::_F); + mFlags.set(Flag::_2); + mStatus = Status::_0; + + Handle::Status ret; + if (request) { + ret = ResourceMgrTask::instance()->requestLoad(this, path, *request); + } else { + LoadRequest temp_request; + ret = ResourceMgrTask::instance()->requestLoad(this, path, temp_request); + } + + if (out_status) + *out_status = ret; + + return ret == Status::_7; + } + + if (out_status) + *out_status = Status::_8; + + return false; +} + +bool Handle::waitForReady() { + if (mTaskHandle.isTaskAttached()) + mTaskHandle.wait(); + + if (mUnit) + mUnit->waitForTask1(); + + return true; +} + +bool Handle::waitForReady(const sead::TickSpan& span) { + if (mTaskHandle.isTaskAttached() && !mTaskHandle.wait(span)) + return false; + + if (mUnit && !mUnit->waitForTask1(span)) + return false; + + return true; +} + +bool Handle::parseResource(Context* context) { + if (mFlags.isOn(Flag::_8)) + return true; + + if (mFlags.isOn(Flag::_4)) + return false; + + if (mTaskHandle.getStatus() == util::ManagedTaskHandle::Status::TaskRemoved || + (mUnit && mUnit->isTask1NotQueued())) { + stubbedLogFunction(); + mStatus = Status::_14; + updateResourceMgrFlag_(); + requestUnload(); + mFlags.set(Flag::_8); + return true; + } + + if (mStatus == Status::_1 || mStatus == Status::_2 || mStatus == Status::_3 || + mStatus == Status::_8 || mStatus == Status::_9 || mStatus == Status::_10 || + mStatus == Status::_11 || mStatus == Status::_12 || mStatus == Status::_13 || + mStatus == Status::_14) { + updateResourceMgrFlag_(); + requestUnload(); + mFlags.set(Flag::_8); + return true; + } + + if (mStatus == Status::_0) + return false; + + if (!mUnit) { + stubbedLogFunction(); + return false; + } + + switch (mUnit->getStatus()) { + case ResourceUnit::Status::_0: + case ResourceUnit::Status::_7: + return false; + case ResourceUnit::Status::_8: + case ResourceUnit::Status::_10: + case ResourceUnit::Status::_11: + case ResourceUnit::Status::_13: + waitForResourceAndParse_(context); + break; + case ResourceUnit::Status::_9: + updateStatusAndUnload_(); + break; + case ResourceUnit::Status::_12: + case ResourceUnit::Status::_15: + mStatus = Status::_9; + updateResourceMgrFlag_(); + requestUnload(); + mFlags.set(Flag::_8); + return true; + case ResourceUnit::Status::_14: + if (mStatus == Status::_7) + mStatus = Status::_4; + updateResourceMgrFlag_(); + break; + default: + break; + } + + mFlags.set(Flag::_8); + return true; +} + +bool Handle::isFlag8Set() const { + return mFlags.isOn(Flag::_8); +} + +// NON_MATCHING: switch +void Handle::updateResourceMgrFlag_() { + sead::FixedSafeString<128> path("***"); + if (mUnit) + path = mUnit->mPath; + + bool warn = true; + switch (mStatus) { + case Status::_3: + if (!mUnit || !mUnit->mArena1->isFlag1Set()) + break; + if (!returnFalse()) + warn = false; + break; + case Status::_4: + static_cast<void>(static_cast<volatile ResourceUnit*>(mUnit)->mStatusFlags); + if (!returnFalse()) + warn = false; + break; + case Status::_5: + case Status::_6: + case Status::_8: + if (!returnFalse()) + warn = false; + break; + default: + break; + } + + if (warn) + stubbedLogFunction(); + + if (mStatus != Status::_3 || !mUnit || !mUnit->mArena1) + return; + + auto* heap = mUnit->mArena1->getHeap(); + + if (!mUnit->mArena1->isFlag1Set() || returnFalse()) + stubbedLogFunction(); + + if (!mUnit->mArena1->isFlag10Set()) + return; + + const s32 type = + (heap->getName().startsWith("Sound") || heap->getName().startsWith("Audio")) ? 0 : 1; + res::ResourceMgrTask::instance()->setFlag2000Or5000(type); +} + +void Handle::updateStatusAndUnload_() { + auto* unit = mUnit; + if (unit && unit->isStatus9_12_15()) { + mStatus = [&] { + if (unit->mStatusFlags.isOn(ResourceUnit::StatusFlag::FailedMaybe)) + return Status::_1; + if (unit->mStatusFlags.isOn(ResourceUnit::StatusFlag::FileSizeIsZero)) + return Status::_2; + if (unit->mStatusFlags.isOn(ResourceUnit::StatusFlag::_400)) + return Status::_9; + if (unit->mStatusFlags.isOn(ResourceUnit::StatusFlag::FileSizeExceedsAllocSize)) + return Status::_10; + if (unit->mStatusFlags.isOn(ResourceUnit::StatusFlag::_1000)) + return Status::_11; + if (unit->mStatusFlags.isOn(ResourceUnit::StatusFlag::FileOrResInstanceTooLargeForHeap)) + return Status::_12; + if (unit->mStatusFlags.isOn(ResourceUnit::StatusFlag::LoadFailed)) + return Status::_13; + +#ifdef MATCHING_HACK_NX_CLANG + asm(""); +#endif + return Status::_3; + }(); + } + updateResourceMgrFlag_(); + requestUnload(); +} + +void Handle::requestUnload2() { + requestUnload(); +} + +void Handle::unload() { + if (!mFlags.isOn(Flag::_2)) + return; + + mFlags.reset(Flag::_7); + mFlags.set(Flag::_4); + + if (mTaskHandle.hasTask()) { + mTaskHandle.removeTaskFromQueue(); + if (!mUnit) { + stubbedLogFunction(); + mStatus = Status::_14; + return; + } + } + + if (mUnit) + ResourceMgrTask::instance()->requestUnloadForSync(this); +} + +void Handle::unloadAndResetUnitFlag20000() { + if (!mFlags.isOn(Flag::_2)) + return; + + mFlags.reset(Flag::_7); + mFlags.set(Flag::_4); + + if (mTaskHandle.hasTask()) { + mTaskHandle.removeTaskFromQueue(); + if (!mUnit) { + stubbedLogFunction(); + mStatus = Status::_14; + return; + } + } + + ResourceUnit* unit = mUnit; + if (!unit) + return; + + stubbedLogFunction(); + unit->mStatusFlags.reset(ResourceUnit::StatusFlag::_20000); + ResourceMgrTask::instance()->requestUnloadForSync(this); +} + +void Handle::resetUnitFlag20000IfSuccess() { + if (mFlags.isOff(Flag::_2)) + return; + + ResourceUnit* unit = mUnit; + + if (isBusy()) + return; + + if (!mUnit || !mUnit->isParseOk()) + return; + + if (unit) + unit->mStatusFlags.reset(ResourceUnit::StatusFlag::_20000); +} + +bool Handle::isBusy() const { + if (mTaskHandle.isTaskAttached()) + return true; + + if (mFlags.isOn(Flag::_2) && mUnit) + return mUnit->isTask1ActiveOrStatus7(); + + return false; +} + +bool Handle::isReadyOrNeedsParse() const { + if ((mFlags.getDirect() & 0xA) != u32(Flag::_2) || isBusy()) + return false; + + if (isReady()) + return true; + + return mUnit && mUnit->needsParse(); +} + +bool Handle::isReady() const { + if (isSuccess()) + return true; + + return checkLoadStatus(); +} + +bool Handle::checkLoadStatus() const { + if (isBusy()) + return false; + + bool ok = false; + if (mFlags.isOn(Flag::_2) && mUnit) + ok = mUnit->isStatus9_12_15(); + + ok |= mStatus == Status::_1 || mStatus == Status::_2 || mStatus == Status::_3 || + mStatus == Status::_8 || mStatus == Status::_9 || mStatus == Status::_10 || + mStatus == Status::_11 || mStatus == Status::_12 || mStatus == Status::_13 || + mStatus == Status::_14; + + return ok; +} + +sead::SafeString Handle::makeEmptyString() { + return sead::SafeString::cEmptyString; +} + +void Handle::waitForResourceAndParse_(Context* context) { + if (!mUnit) { + updateResourceMgrFlag_(); + return; + } + + if (mUnit->waitForResourceAndParse(context)) { + if (mStatus == Status::_7) + mStatus = Status::_4; + updateResourceMgrFlag_(); + return; + } + + mStatus = Status::_9; + updateResourceMgrFlag_(); + requestUnload(); +} + } // namespace ksys::res diff --git a/src/KingSystem/Resource/resHandle.h b/src/KingSystem/Resource/resHandle.h index c025a278..45d6af0b 100644 --- a/src/KingSystem/Resource/resHandle.h +++ b/src/KingSystem/Resource/resHandle.h @@ -13,6 +13,7 @@ class DirectResource; namespace ksys::res { +class Context; class ILoadRequest; class ResourceUnit; @@ -43,15 +44,42 @@ public: Status getStatus() const; - sead::DirectResource* load(const sead::SafeString& path, const ILoadRequest& request, + sead::DirectResource* getResource() const; + bool isSuccess() const; + sead::DirectResource* getResourceUnchecked() const; + + sead::DirectResource* load(const sead::SafeString& path, const ILoadRequest* request, Status* out_status = nullptr); + bool isFlag2Set() const; + bool requestLoad(const sead::SafeString& path, const ILoadRequest* request, + Status* out_status = nullptr); + + bool waitForReady(); + bool waitForReady(const sead::TickSpan& span); + bool parseResource(Context* context); + bool isFlag8Set() const; + + void requestUnload(); void unload(); + // TODO: how does this differ? + void requestUnload2(); + void unloadAndResetUnitFlag20000(); + void resetUnitFlag20000IfSuccess(); + + bool isBusy() const; + bool isReadyOrNeedsParse() const; + bool isReady() const; + bool checkLoadStatus() const; + + sead::SafeString makeEmptyString(); void setUnit(ResourceUnit* unit) { mUnit = unit; } bool isLinked() const { return mListNode.isLinked(); } + void setStatusForResourceMgr_(const Status& status); + static size_t getListNodeOffset() { return offsetof(Handle, mListNode); } private: @@ -61,8 +89,15 @@ private: _4 = 0x4, _7 = 0x7, _8 = 0x8, + _F = 0xF, }; + void updateResourceMgrFlag_(); + void updateStatusAndUnload_(); + void waitForResourceAndParse_(Context* context); + + inline bool checkPathChange_(const sead::SafeString& path); + sead::TypedBitFlag<Flag> mFlags = Flag::_1; Status mStatus = Status::_0; ResourceUnit* mUnit = nullptr; diff --git a/src/KingSystem/Resource/resInfoContainer.cpp b/src/KingSystem/Resource/resInfoContainer.cpp index 00bf40b9..204e9dd7 100644 --- a/src/KingSystem/Resource/resInfoContainer.cpp +++ b/src/KingSystem/Resource/resInfoContainer.cpp @@ -34,7 +34,7 @@ bool ResourceInfoContainer::loadResourceSizeTable() { req.mRequester = "ResourceInfoContainer"; req.mPath = "System/Resource/ResourceSizeTable.product.rsizetable"; req._c = 1; - return sead::DynamicCast<Resource>(mRstbHandle.load(req.mPath, req)); + return sead::DynamicCast<Resource>(mRstbHandle.load(req.mPath, &req)); }; const Resource* resource = load_res(); diff --git a/src/KingSystem/Resource/resLoadRequest.cpp b/src/KingSystem/Resource/resLoadRequest.cpp deleted file mode 100644 index e8e2181f..00000000 --- a/src/KingSystem/Resource/resLoadRequest.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "KingSystem/Resource/resLoadRequest.h" - -namespace ksys::res { - -ILoadRequest::~ILoadRequest() { - ; -} - -LoadRequest::LoadRequest() = default; - -LoadRequest::LoadRequest(s32 load_data_alignment, u32 arg_c, bool arg_20) - : _20(arg_20), mLoadDataAlignment(load_data_alignment) { - _c = arg_c; -} - -SimpleLoadRequest::SimpleLoadRequest() = default; - -SimplePackedLoadRequest::SimplePackedLoadRequest() = default; - -} // namespace ksys::res diff --git a/src/KingSystem/Resource/resResourceMgrTask.h b/src/KingSystem/Resource/resResourceMgrTask.h index 2544c8e1..df1117e9 100644 --- a/src/KingSystem/Resource/resResourceMgrTask.h +++ b/src/KingSystem/Resource/resResourceMgrTask.h @@ -137,11 +137,13 @@ public: bool isFlag4Set() const; - s32 requestLoad(Handle* handle, const sead::SafeString& path, const ILoadRequest& request); + Handle::Status requestLoad(Handle* handle, const sead::SafeString& path, + const ILoadRequest& request); void addSExtensionPrefix(sead::StringBuilder& builder) const; - s32 requestLoadForSync(Handle* handle, const sead::SafeString& path, - const ILoadRequest& request); - s32 requestUnload(Handle* handle); + Handle::Status requestLoadForSync(Handle* handle, const sead::SafeString& path, + const ILoadRequest& request); + void requestUnload(Handle* handle); + void requestUnloadForSync(Handle* handle); void registerUnit(ResourceUnit* unit); void deregisterUnit(ResourceUnit* unit); diff --git a/src/KingSystem/Resource/resUnit.cpp b/src/KingSystem/Resource/resUnit.cpp index a93e5266..ee252d84 100644 --- a/src/KingSystem/Resource/resUnit.cpp +++ b/src/KingSystem/Resource/resUnit.cpp @@ -50,7 +50,7 @@ bool ResourceUnit::init(const ResourceUnit::InitArg& arg) { request.mRequester = "ResourceUnit"; request._c = 2; request.mPack = arg.load_req->mPackHandle; - mArchiveRes = sead::DynamicCast<sead::ArchiveRes>(mArchiveResHandle.load("", request)); + mArchiveRes = sead::DynamicCast<sead::ArchiveRes>(mArchiveResHandle.load("", &request)); } mMapNode.key().setKey(mPath); @@ -123,7 +123,7 @@ ResourceUnit::~ResourceUnit() { void ResourceUnit::unloadArchiveRes() { if (mArchiveRes) { mArchiveRes = nullptr; - mArchiveResHandle.unload(); + mArchiveResHandle.requestUnload(); } } @@ -141,11 +141,16 @@ ResourceUnit::Status ResourceUnit::getStatus() const { return mStatus; } +static const ResourceUnit::Status sUnitStatusTransitionTable[] = { + ResourceUnit::Status::_8, ResourceUnit::Status::_11, ResourceUnit::Status::_11, + ResourceUnit::Status::_14, ResourceUnit::Status::_14, +}; + // NON_MATCHING: ldr + sxtw -> ldrsw void ResourceUnit::updateStatus() { - static const Status sMap[] = {Status::_8, Status::_11, Status::_11, Status::_14, Status::_14}; - if (Status::_2 <= mStatus && mStatus <= Status::_6) - mStatus = sMap[s32(mStatus)]; + const s32 idx = mStatus; + if (Status::_2 <= idx && idx <= Status::_6) + mStatus = sUnitStatusTransitionTable[idx]; } bool ResourceUnit::isTask1NotQueued() const { @@ -168,6 +173,13 @@ bool ResourceUnit::isStatus1() const { return mStatus == Status::_1; } +bool ResourceUnit::needsParse() const { + auto* res = sead::DynamicCast<Resource>(mResource); + if (mStatus != Status::_8 && mStatus != Status::_11) + return false; + return res && res->needsParse(); +} + bool ResourceUnit::isStatus9_12_15() const { return mStatus == Status::_9 || mStatus == Status::_12 || mStatus == Status::_15; } @@ -176,13 +188,15 @@ bool ResourceUnit::isStatus9_12_15() const { bool ResourceUnit::isParseOk() const { auto* ksys_res = sead::DynamicCast<res::Resource>(mResource); - if (mStatus == Status::_14) + const auto status = mStatus.value(); + + if (status == Status::_14) return true; - if (mStatus == Status::_8 && !ksys_res) + if (status == Status::_8 && !ksys_res) return mResource != nullptr; - if (mStatus == Status::_8 && ksys_res) + if (status == Status::_8 && ksys_res) return !ksys_res->needsParse(); return false; diff --git a/src/KingSystem/Resource/resUnit.h b/src/KingSystem/Resource/resUnit.h index 20e6f85e..8cbfa907 100644 --- a/src/KingSystem/Resource/resUnit.h +++ b/src/KingSystem/Resource/resUnit.h @@ -2,6 +2,7 @@ #include <KingSystem/Utils/StrTreeMap.h> #include <hostio/seadHostIONode.h> +#include <prim/seadEnum.h> #include <prim/seadRuntimeTypeInfo.h> #include <prim/seadSafeString.h> #include <prim/seadTypedBitFlag.h> @@ -48,24 +49,7 @@ private: class ResourceUnit : public sead::hostio::Node { SEAD_RTTI_BASE(ResourceUnit) public: - enum class Status { - _0 = 0, - _1 = 1, - _2 = 2, - _3 = 3, - _4 = 4, - _5 = 5, - _6 = 6, - _7 = 7, - _8 = 8, - _9 = 9, - _10 = 10, - _11 = 11, - _12 = 12, - _13 = 13, - _14 = 14, - _15 = 15, - }; + SEAD_ENUM(Status, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) struct InitArg { InitArg() = default; @@ -119,6 +103,7 @@ public: bool isStatus0() const; bool isTask1ActiveOrStatus7() const; bool isStatus1() const; + bool needsParse() const; bool isStatus9_12_15() const; bool isParseOk() const; bool isStatusFlag8000Set() const; |
