#include #include #include #include "KingSystem/Resource/resLoadRequest.h" #include "KingSystem/System/StarterPackMgr.h" #include "KingSystem/System/UI/ArcResource.h" #include "KingSystem/System/UI/LayoutResourceMgr.h" namespace ksys::ui { SEAD_SINGLETON_DISPOSER_IMPL(LayoutResourceMgr) void LayoutResourceMgr::init(sead::Heap* heap) { mMsgPackHandle = new (heap) res::Handle; mLangFontHandle = new (heap) res::Handle; mVersionHandle = new (heap) res::Handle; int count; switch (sead::EnvUtil::getRegionLanguage().value()) { case sead::RegionLanguageID::KRko: case sead::RegionLanguageID::CNzh: case sead::RegionLanguageID::TWzh: count = cExtraLangFontCount; break; default: count = 0; break; } for (int i = 0; i < count; i++) { mExtraLangFontHandles.pushBack(new (heap) res::Handle); } if (count > 0) { mZeldaGlyphHandle = new (heap) res::Handle; } } u8* LayoutResourceMgr::loadMsgPack(u32* size) { mMsgPackHandle->resetUnitFlag20000IfSuccess(); mMsgPackHandle->unload(); res::LoadRequest req; req.mRequester = "LayoutResourceMgr"; req._22 = true; req._21 = true; req.mLoadDataAlignment = 0x80; req._26 = false; req.mPackHandle = StarterPackMgr::instance()->getBootupLangPack(); sead::FixedSafeString<0x20> path; path.format("Message/Msg_%s.product.sarc", sead::EnvUtil::getRegionLanguage().text()); res::Handle::Status status; auto* resource = sead::DynamicCast(mMsgPackHandle->load(path, &req, &status)); *size = resource->getRawSize(); return resource->getRawData(); } void LayoutResourceMgr::loadLangFont(sead::Heap* heap) { mLangFontHandle->resetUnitFlag20000IfSuccess(); mLangFontHandle->unload(); mLangFontResource = nullptr; res::LoadRequest req; req.mRequester = "LayoutResourceMgr"; req._22 = true; req.mLoadDataAlignment = 0x1000; req._26 = false; sead::FixedSafeString<0x20> path; path.format("Font/Font_%s.bfarc", sead::EnvUtil::getRegion().text()); mLangFontHandle->requestLoad(path, &req, nullptr); } constexpr const char* sExtraLangFontFiles[LayoutResourceMgr::cExtraLangCount * LayoutResourceMgr::cExtraLangFontCount] = { "AsiaKCUBE-R", "AsiaKDREAM2R", "AsiaKDREAM4R", "AsiaKDREAM7R", "DFP_GBZY9", "DFP_GB_H3", "DFP_GB_H5", "DFHEI5A", "DFT_ZY9", "DFT_B3", "DFT_B5", "DFT_B9"}; void LayoutResourceMgr::loadExtraLangFonts(sead::Heap* heap) { sead::RegionLanguageID lang_id = sead::EnvUtil::getRegionLanguage(); auto* fonts = sExtraLangFontFiles; for (int i = 0; i <= cExtraLangCount; i++) { if (lang_id.value() == sead::RegionLanguageID::KRko + i) { break; } if (i == cExtraLangCount - 1) { return; } fonts += cExtraLangFontCount; } res::LoadRequest req; req.mRequester = "ui::LayoutResourceMgr"; req._26 = false; res::Handle::Status status = res::Handle::Status::NoFile; for (int i = 0; i < cExtraLangFontCount; ++i) { auto* handle = mExtraLangFontHandles[i]; sead::FixedSafeString<0x20> path; #ifdef MATCHING_HACK_NX_CLANG asm(""); #endif path.format("Font/%s.bfttf", fonts[i]); handle->requestLoad(path, &req, &status); } mZeldaGlyphHandle->requestLoad("Font/ZeldaGlyphs-v2-Deco.bfotf", &req, &status); nn::pl::RequestSharedFontLoad(nn::pl::SharedFontType::STANDARD); } bool LayoutResourceMgr::checkLangFontReady() { if (mLangFontResource) { return true; } if (!mLangFontHandle->isReady()) { return false; } mLangFontResource = sead::DynamicCast(mLangFontHandle->getResource()); return true; } bool LayoutResourceMgr::checkExtraLangFontsReady() const { switch (sead::EnvUtil::getRegionLanguage().value()) { case sead::RegionLanguageID::KRko: case sead::RegionLanguageID::CNzh: case sead::RegionLanguageID::TWzh: break; default: return true; } for (const auto& handle : mExtraLangFontHandles) { if (!handle.isReady()) { return false; } } if (!mZeldaGlyphHandle || mZeldaGlyphHandle->isReady()) { return nn::pl::GetSharedFontLoadState(nn::pl::SharedFontType::STANDARD) == nn::pl::LoadState::LOADED; } return false; } void LayoutResourceMgr::loadVersion() { res::LoadRequest req; req.mRequester = "LayoutResourceMgr"; req._26 = false; mVersionHandle->requestLoad("System/Version.txt", &req, nullptr); } bool LayoutResourceMgr::checkVersionReady() { if (!mVersionHandle) { return true; } if (mVersionHandle->isReady()) { auto* resource = sead::DynamicCast(mVersionHandle->getResource()); instance()->mVersionString.copy(reinterpret_cast(resource->getRawData()), static_cast(resource->getRawSize())); delete mVersionHandle; mVersionHandle = nullptr; return true; } return false; } void LayoutResourceMgr::loadCommonLayoutArchive(sead::ExpHeap* heap) { mArcResourceMgr->loadArchive(heap, "Layout/Common.sblarc"); } void LayoutResourceMgr::loadTitleLayout(sead::Heap* heap) { mTitleLayout.allocate(heap); res::LoadRequest req; req.mRequester = "ui::LayoutResourceMgr"; req.mLoadDataAlignment = 0x1000; req._22 = false; req._26 = false; req.mLaneId = 2; res::Handle::Status status = res::Handle::Status::NoFile; mTitleLayout.getHandle()->requestLoad("Layout/Title.blarc", &req, &status); } bool LayoutResourceMgr::loadTitleLayoutResource() { return loadArcResource(mTitleLayout, "Title"); } void LayoutResourceMgr::unloadTitleLayout() { mTitleLayout.deallocate(); } bool LayoutResourceMgr::loadHorseLayout(sead::Heap* heap) { const auto lock = sead::makeScopedLock(mCriticalSection); if (mHorseLayoutLoadCount++) { return false; } mHorseLayout.allocate(heap); res::LoadRequest req; req.mRequester = "ui::LayoutResourceMgr"; req.mLoadDataAlignment = 0x1000; req._22 = false; req._26 = true; req.mLaneId = 2; res::Handle::Status status = res::Handle::Status::NoFile; mHorseLayout.getHandle()->requestLoad("Layout/Horse.blarc", &req, &status); return true; } bool LayoutResourceMgr::loadHorseLayoutResource() { const auto lock = sead::makeScopedLock(mCriticalSection); return loadArcResource(mHorseLayout, "Horse"); } bool LayoutResourceMgr::hasHorseLayoutLoadFailure() const { if (mHorseLayout.getHandle()) { if (mHorseLayout.getHandle()->isReady() && !mHorseLayout.getHandle()->isSuccess()) { return true; } } return false; } bool LayoutResourceMgr::unloadHorseLayout() { const auto lock = sead::makeScopedLock(mCriticalSection); int old_count = mHorseLayoutLoadCount--; if (mHorseLayoutLoadCount == 0) { mHorseLayout.deallocate(); return true; } return old_count < 2; } bool LayoutResourceMgr::loadArcResource(Archive& archive, const char* name) { if (archive.getResource()) { return true; } if (!archive.getHandle()->isReady()) { return false; } if (archive.getHandle()->isSuccess()) { auto* resource = sead::DynamicCast(archive.getHandle()->getResource()); if (resource) { auto* arc_resource = reinterpret_cast(archive.mResourceStorage); arc_resource->init(mArcResourceMgr, name, resource->getRawData(), archive.mHandle); archive.mResource = arc_resource; mArcResourceMgr->addArchive(archive.getResource()); } } return true; } void LayoutResourceMgr::unloadA8() { _a8.deallocate(); } } // namespace ksys::ui