From f97b29462b6920a6648fa5b72fb890899e0df27c Mon Sep 17 00:00:00 2001 From: kiwi515 <49212064+kiwi515@users.noreply.github.com> Date: Sun, 5 Apr 2026 23:15:47 -0400 Subject: [PATCH] RPSysResourceManager WIP --- config/RSPE01_01/symbols.txt | 32 +- docs/contributing.md | 4 +- .../Pack/RPKernel/IRPSysKokeshiBodyManager.h | 1 - include/Pack/RPKernel/RPSysAppMiiManager.h | 9 +- include/Pack/RPKernel/RPSysFile.h | 10 +- include/Pack/RPParty.h | 6 + include/Pack/RPParty/RPPartyBodyManager.h | 54 ++ include/Pack/RPSports.h | 7 + include/Pack/RPSports/RPSportsAppMiiManager.h | 35 + include/Pack/RPSports/RPSportsBodyManager.h | 54 ++ include/Pack/RPSystem/RPSysResourceManager.h | 296 +++++--- include/Pack/RPSystem/RPSysSceneCreator.h | 4 +- include/egg/core/eggArchive.h | 2 +- include/egg/core/eggDvdRipper.h | 8 +- src/Pack/RPSystem/RPSysResourceManager.cpp | 637 ++++++++++++++++++ src/Pack/RPSystem/RPSysSaveDataMgr.cpp | 6 +- 16 files changed, 1037 insertions(+), 128 deletions(-) create mode 100644 include/Pack/RPParty.h create mode 100644 include/Pack/RPParty/RPPartyBodyManager.h create mode 100644 include/Pack/RPSports.h create mode 100644 include/Pack/RPSports/RPSportsAppMiiManager.h create mode 100644 include/Pack/RPSports/RPSportsBodyManager.h create mode 100644 src/Pack/RPSystem/RPSysResourceManager.cpp diff --git a/config/RSPE01_01/symbols.txt b/config/RSPE01_01/symbols.txt index 2d6400b10..36958eef4 100644 --- a/config/RSPE01_01/symbols.txt +++ b/config/RSPE01_01/symbols.txt @@ -7002,25 +7002,25 @@ fn_80186D2C = .text:0x80186D2C; // type:function size:0x4 fn_80186D30 = .text:0x80186D30; // type:function size:0x110 fn_80186E40 = .text:0x80186E40; // type:function size:0x58 fn_80186E98 = .text:0x80186E98; // type:function size:0x1C -fn_80186EB4 = .text:0x80186EB4; // type:function size:0xEC -fn_80186FA0 = .text:0x80186FA0; // type:function size:0x254 -fn_801871F4 = .text:0x801871F4; // type:function size:0x9C +LoadFromDVD__20RPSysResourceManagerFPCcPQ23EGG4HeapQ33EGG9DvdRipper15EAllocDirectionPl = .text:0x80186EB4; // type:function size:0xEC +LoadCompressed__20RPSysResourceManagerFPCcPQ23EGG4Heap = .text:0x80186FA0; // type:function size:0x254 +LoadStaticLocalArchive__20RPSysResourceManagerFPCc = .text:0x801871F4; // type:function size:0x9C GetGameSoundLocalPath__20RPSysResourceManagerFPcUll = .text:0x80187290; // type:function size:0x70 GetGameSoundCommonPath__20RPSysResourceManagerFPcUll = .text:0x80187300; // type:function size:0x6C GetStaticSoundLocalPath__20RPSysResourceManagerFPcUl = .text:0x8018736C; // type:function size:0x7C GetStaticSoundCommonPath__20RPSysResourceManagerFPcUl = .text:0x801873E8; // type:function size:0x64 -fn_8018744C = .text:0x8018744C; // type:function size:0x68 -fn_801874B4 = .text:0x801874B4; // type:function size:0x150 -fn_80187604 = .text:0x80187604; // type:function size:0x1D0 +LoadKokeshiArchive__20RPSysResourceManagerFv = .text:0x8018744C; // type:function size:0x68 +LoadCacheArchives__20RPSysResourceManagerFv = .text:0x801874B4; // type:function size:0x150 +LoadStaticArchives__20RPSysResourceManagerFv = .text:0x80187604; // type:function size:0x1D0 RemoveFromFileList__20RPSysResourceManagerFP9RPSysFile = .text:0x801877D4; // type:function size:0x8 IsExist__20RPSysResourceManagerFPCc = .text:0x801877DC; // type:function size:0x60 -fn_8018783C = .text:0x8018783C; // type:function size:0x3C -fn_80187878 = .text:0x80187878; // type:function size:0x4C -fn_801878C4 = .text:0x801878C4; // type:function size:0xA0 -fn_80187964 = .text:0x80187964; // type:function size:0xA8 -fn_80187A0C = .text:0x80187A0C; // type:function size:0x9C -fn_80187AA8 = .text:0x80187AA8; // type:function size:0x40 -fn_80187AE8 = .text:0x80187AE8; // type:function size:0x6C +GetMessageResource__20RPSysResourceManagerFPCc = .text:0x8018783C; // type:function size:0x3C +GetFileFromArchive__20RPSysResourceManagerFPQ23EGG7ArchivePCcPUl = .text:0x80187878; // type:function size:0x4C +LoadGameStageArchive__20RPSysResourceManagerFPCc = .text:0x801878C4; // type:function size:0xA0 +LoadGameLocalArchive__20RPSysResourceManagerFlPQ23EGG4Heap = .text:0x80187964; // type:function size:0xA8 +LoadGameCommonArchive__20RPSysResourceManagerFlPQ23EGG4Heap = .text:0x80187A0C; // type:function size:0x9C +__dt__20RPSysResourceManagerFv = .text:0x80187AA8; // type:function size:0x40 +CreateInstance__20RPSysResourceManagerFv = .text:0x80187AE8; // type:function size:0x6C fn_80187B54 = .text:0x80187B54; // type:function size:0x40 fn_80187B94 = .text:0x80187B94; // type:function size:0xC fn_80187BA0 = .text:0x80187BA0; // type:function size:0x70 @@ -15058,7 +15058,7 @@ lbl_80382438 = .rodata:0x80382438; // type:object size:0x18 @stringBase0 = .rodata:0x80382470; // type:object size:0xF2 scope:local data:string_table lbl_80382568 = .rodata:0x80382568; // type:object size:0x48 lbl_803825B0 = .rodata:0x803825B0; // type:object size:0xC data:string -lbl_803825C0 = .rodata:0x803825C0; // type:object size:0x38 data:4byte +CACHED_SCENES__20RPSysResourceManager = .rodata:0x803825C0; // type:object size:0x38 data:4byte lbl_803825F8 = .rodata:0x803825F8; // type:object size:0xE data:string lbl_80382606 = .rodata:0x80382606; // type:object size:0xD data:string lbl_80382613 = .rodata:0x80382613; // type:object size:0xE data:string @@ -18566,7 +18566,7 @@ __vt__15RPSysGameConfig = .data:0x803B9808; // type:object size:0xC scope:global __vt__19RPSysPrimTagParm = .data:0x803B9814; // type:object size:0x14 scope:weak __vt__18RPSysStringTagParm = .data:0x803B9828; // type:object size:0x14 scope:global __vt__12RPSysTagParm = .data:0x803B983C; // type:object size:0x14 scope:global -scStaticPaths__20RPSysResourceManager = .data:0x803B9850; // type:object size:0x10 scope:global +STATIC_DIR_NAMES__20RPSysResourceManager = .data:0x803B9850; // type:object size:0x10 scope:global __vt__20RPSysResourceManager = .data:0x803B9860; // type:object size:0x10 scope:global __vt__16RPSysQueuedScene = .data:0x803B9870; // type:object size:0x10 scope:global __vt__17RPSysCommonObject = .data:0x803B9880; // type:object size:0x14 scope:global @@ -20439,7 +20439,7 @@ scResFileFullPathName = .sdata:0x804BDB60; // type:object size:0x4 scope:local d scFileNames = .sdata:0x804BDB68; // type:object size:0x8 scope:local scFirstDirectory = .sdata:0x804BDB70; // type:object size:0x4 scope:local data:4byte scSecondDirectory = .sdata:0x804BDB74; // type:object size:0x4 scope:local data:4byte -lbl_804BDB78 = .sdata:0x804BDB78; // type:object size:0x8 data:4byte +KOKESHI_ARCHIVE_PATH__20RPSysResourceManager = .sdata:0x804BDB78; // type:object size:0x4 data:4byte GAME_DISK_NAME__14RPSysDvdStatus = .sdata:0x804BDB80; // type:object size:0x4 data:4byte lbl_804BDB88 = .sdata:0x804BDB88; // type:object size:0x8 data:4byte lbl_804BDB90 = .sdata:0x804BDB90; // type:object size:0x8 data:4byte diff --git a/docs/contributing.md b/docs/contributing.md index 2208b8583..a6e073015 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -325,14 +325,14 @@ public: // 2. PROTECTED ACCESS protected: - // 7. Non-static functions + // 7. All other functions const Fruit& GetFruit(int i) const { return mFruits[i]; } // 3. PRIVATE ACCESS private: - // 7. Non-static functions + // 7. All other functions void Clear(); // 8. Constant, static members diff --git a/include/Pack/RPKernel/IRPSysKokeshiBodyManager.h b/include/Pack/RPKernel/IRPSysKokeshiBodyManager.h index 3e617cdae..9f80e9302 100644 --- a/include/Pack/RPKernel/IRPSysKokeshiBodyManager.h +++ b/include/Pack/RPKernel/IRPSysKokeshiBodyManager.h @@ -6,7 +6,6 @@ #include - //! @addtogroup rp_kernel //! @{ diff --git a/include/Pack/RPKernel/RPSysAppMiiManager.h b/include/Pack/RPKernel/RPSysAppMiiManager.h index 423beace8..5faa7927b 100644 --- a/include/Pack/RPKernel/RPSysAppMiiManager.h +++ b/include/Pack/RPKernel/RPSysAppMiiManager.h @@ -2,10 +2,10 @@ #define RP_KERNEL_APP_MII_MANAGER_H #include -#include - #include +#include + //! @addtogroup rp_kernel //! @{ @@ -33,6 +33,11 @@ class RPSysAppMiiManager { */ virtual ~RPSysAppMiiManager() {} // at 0x8 + /** + * @brief Loads the Mii data resources + */ + virtual void LoadResource() = 0; // at 0xC + /** * @brief Gets the capacity of the Mii buffer */ diff --git a/include/Pack/RPKernel/RPSysFile.h b/include/Pack/RPKernel/RPSysFile.h index f0ce534d1..9d73d99e3 100644 --- a/include/Pack/RPKernel/RPSysFile.h +++ b/include/Pack/RPKernel/RPSysFile.h @@ -13,6 +13,10 @@ * @brief Cached resource file */ class RPSysFile : public EGG::Disposer { +public: + //! Maximum file path length + static const u32 PATH_MAX = 128; + public: /** * @brief Constructor @@ -46,7 +50,7 @@ class RPSysFile : public EGG::Disposer { /** * @brief Gets the data of this file */ - const void* GetData() const { + const u8* GetData() const { return mpData; } @@ -54,10 +58,6 @@ class RPSysFile : public EGG::Disposer { //! Linked-list node used for cache lists NW4R_UT_LIST_LINK_DECL(); // at 0x10 -private: - //! Maximum file path length - static const u32 PATH_MAX = 128; - private: //! File path char mPath[PATH_MAX]; // at 0x18 diff --git a/include/Pack/RPParty.h b/include/Pack/RPParty.h new file mode 100644 index 000000000..0147f07be --- /dev/null +++ b/include/Pack/RPParty.h @@ -0,0 +1,6 @@ +#ifndef RP_PUBLIC_PARTY_H +#define RP_PUBLIC_PARTY_H + +#include + +#endif diff --git a/include/Pack/RPParty/RPPartyBodyManager.h b/include/Pack/RPParty/RPPartyBodyManager.h new file mode 100644 index 000000000..83a7d48aa --- /dev/null +++ b/include/Pack/RPParty/RPPartyBodyManager.h @@ -0,0 +1,54 @@ +#ifndef RP_PARTY_BODY_MANAGER_H +#define RP_PARTY_BODY_MANAGER_H +#include + +#include + +//! @addtogroup rp_party +//! @{ + +/** + * @brief Party Pack Mii body manager + */ +class RPPartyBodyManager : public IRPSysKokeshiBodyManager { +public: + /** + * @brief Constructor + */ + RPPartyBodyManager(); + + /** + * @brief Destructor + */ + virtual ~RPPartyBodyManager(); // at 0x2C + + virtual u16 GetFriendClothesStartIndex(); // at 0x8 + virtual u16 GetFriendClothesIndexRange(); // at 0xC + + virtual const char* GetBodyFileName(u16 bodyType, + RFLSex sex); // at 0x10 + + virtual u16 GetBodyModelIndex(u16 bodyType, RFLSex sex, u32 height, + u32 build); // at 0x14 + + virtual const char* GetClothesFileName(); // at 0x18 + + virtual void GetClothesName(u16 clothesType, RFLSex sex, + const char** ppNameA, + const char** ppNameB); // at 0x1C + + virtual void GetHeadJointMtx(u16 bodyType, RPGrpModel* pBodyModel, + EGG::Matrix34f* pMtx); // at 0x20 + + virtual void GetLeftHandJointMtx(u16 bodyType, RPGrpModel* pBodyModel, + EGG::Matrix34f* pMtx); // at 0x24 + virtual void GetRightHandJointMtx(u16 bodyType, RPGrpModel* pBodyModel, + EGG::Matrix34f* pMtx); // at 0x28 + +private: + // . . . +}; + +//! @} + +#endif diff --git a/include/Pack/RPSports.h b/include/Pack/RPSports.h new file mode 100644 index 000000000..9568e059d --- /dev/null +++ b/include/Pack/RPSports.h @@ -0,0 +1,7 @@ +#ifndef RP_PUBLIC_SPORTS_H +#define RP_PUBLIC_SPORTS_H + +#include +#include + +#endif diff --git a/include/Pack/RPSports/RPSportsAppMiiManager.h b/include/Pack/RPSports/RPSportsAppMiiManager.h new file mode 100644 index 000000000..8102dada7 --- /dev/null +++ b/include/Pack/RPSports/RPSportsAppMiiManager.h @@ -0,0 +1,35 @@ +#ifndef RP_SPORTS_APP_MII_MANAGER_H +#define RP_SPORTS_APP_MII_MANAGER_H +#include + +#include + +#include + +//! @addtogroup rp_sports +//! @{ + +/** + * @brief Sports Pack Mii data manager + */ +class RPSportsAppMiiManager : public RPSysAppMiiManager { +public: + /** + * @brief Constructor + * + * @param pHeap Heap to use for allocations + */ + RPSportsAppMiiManager(EGG::Heap* pHeap); + + /** + * @brief Loads the Mii data resources + */ + virtual void LoadResource(); // at 0xC + +private: + // . . . +}; + +//! @} + +#endif diff --git a/include/Pack/RPSports/RPSportsBodyManager.h b/include/Pack/RPSports/RPSportsBodyManager.h new file mode 100644 index 000000000..6e3f7e149 --- /dev/null +++ b/include/Pack/RPSports/RPSportsBodyManager.h @@ -0,0 +1,54 @@ +#ifndef RP_SPORTS_BODY_MANAGER_H +#define RP_SPORTS_BODY_MANAGER_H +#include + +#include + +//! @addtogroup rp_sports +//! @{ + +/** + * @brief Sports Pack Mii body manager + */ +class RPSportsBodyManager : public IRPSysKokeshiBodyManager { +public: + /** + * @brief Constructor + */ + RPSportsBodyManager(); + + /** + * @brief Destructor + */ + virtual ~RPSportsBodyManager(); // at 0x2C + + virtual u16 GetFriendClothesStartIndex(); // at 0x8 + virtual u16 GetFriendClothesIndexRange(); // at 0xC + + virtual const char* GetBodyFileName(u16 bodyType, + RFLSex sex); // at 0x10 + + virtual u16 GetBodyModelIndex(u16 bodyType, RFLSex sex, u32 height, + u32 build); // at 0x14 + + virtual const char* GetClothesFileName(); // at 0x18 + + virtual void GetClothesName(u16 clothesType, RFLSex sex, + const char** ppNameA, + const char** ppNameB); // at 0x1C + + virtual void GetHeadJointMtx(u16 bodyType, RPGrpModel* pBodyModel, + EGG::Matrix34f* pMtx); // at 0x20 + + virtual void GetLeftHandJointMtx(u16 bodyType, RPGrpModel* pBodyModel, + EGG::Matrix34f* pMtx); // at 0x24 + virtual void GetRightHandJointMtx(u16 bodyType, RPGrpModel* pBodyModel, + EGG::Matrix34f* pMtx); // at 0x28 + +private: + // . . . +}; + +//! @} + +#endif diff --git a/include/Pack/RPSystem/RPSysResourceManager.h b/include/Pack/RPSystem/RPSysResourceManager.h index 28b5c5328..46520fe64 100644 --- a/include/Pack/RPSystem/RPSysResourceManager.h +++ b/include/Pack/RPSystem/RPSysResourceManager.h @@ -3,6 +3,8 @@ #include #include +#include +#include #include @@ -13,8 +15,6 @@ // Forward declarations class RPSysFile; -class RPSportsAppMiiManager; -class RPPartyAppMiiManager; /** * @brief Resource cache manager @@ -24,191 +24,303 @@ class RPSysResourceManager { public: /** - * @brief Loads a file from the DVD - * @remark If no heap is specified, the current heap is used instead. - * @see EGG::DvdRipper::EAllocDirection + * @brief Resource list type + */ + enum EList { + EList_FileCache, //!< Cached, compressed files + EList_FileList, //!< Decompressed files ready for access + + EList_Max + }; + +public: + /** + * @brief Gets the path to the common asset folder for the specified scene * - * @param pPath Path to the file - * @param pHeap Heap from which to allocate the buffer - * @param allocDir Direction of heap allocation - * @param[out] pSize Where the file's size will be written + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + * @param id Scene ID (defaults to the current scene) */ - void* LoadFromDVD(const char* pPath, EGG::Heap* pHeap, s32 allocDir, - s32* pSize); + void GetGameCommonPath(char* pBuffer, u32 maxlen, s32 id = -1); /** - * @brief Loads and decompresses a file from the DVD - * @remark If the file already exists in the cache, this function returns - * the cached instance. - * @remark If no heap is specified, the current heap is used instead. + * @brief Loads the common asset archive for the specified scene * - * @param pPath Path to the file - * @param pHeap Heap from which to allocate the buffer + * @param id Scene ID (defaults to the current scene) + * @param pHeap Heap to use for allocations (defaults to the current heap) */ - void* LoadCompressed(const char* pPath, EGG::Heap* pHeap); + static EGG::Archive* LoadGameCommonArchive(s32 id = -1, + EGG::Heap* pHeap = NULL); /** - * @brief Loads the local archive in the specified directory - * @note The "local" archive is always named `local.carc`. + * @brief Gets the path to the local asset folder for the specified scene * - * @param pPath Path to the directory + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + * @param id Scene ID (defaults to the current scene) */ - EGG::Archive* LoadLocalArchive(const char* pPath); + void GetGameLocalPath(char* pBuffer, u32 maxlen, s32 id = -1); /** - * @brief Loads the common archive for the specified scene - * @note The "common" archive is always named `common.carc`. + * @brief Loads the local asset archive for the specified scene * - * @param id Scene ID - * @param pHeap Heap from which to allocate the buffer + * @param id Scene ID (defaults to the current scene) + * @param pHeap Heap to use for allocations (defaults to the current heap) */ - static EGG::Archive* LoadGameCommonArchive(s32 id, EGG::Heap* pHeap); + static EGG::Archive* LoadGameLocalArchive(s32 id = -1, + EGG::Heap* pHeap = NULL); + /** - * @brief Loads the local archive for the specified scene - * @note The "local" archive is always named `local.carc`. + * @brief Gets the path to the stage asset folder for the specified scene * - * @param id Scene ID - * @param pHeap Heap from which to allocate the buffer + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + * @param id Scene ID (defaults to the current scene) */ - static EGG::Archive* LoadGameLocalArchive(s32 id, EGG::Heap* pHeap); + void GetGameStagePath(char* pBuffer, u32 maxlen, s32 id = -1); + /** - * @brief Loads the specified stage archive from the current scene's assets + * @brief Loads the specified archive from the current scene's stage assets * - * @param pName Name of the file in the scene's "Stage" directory + * @param pName Archive name */ static EGG::Archive* LoadGameStageArchive(const char* pName); /** - * @brief Gets the specified file from the specified archive + * @brief Gets the specified file from the provided archive * - * @param pArc Archive which contains the file - * @param pName Name of the file - * @param[out] pSize Where the file's size will be written + * @param pArchive Archive containing the file + * @param pName File name + * @param[out] pSize Size of the specified file */ - static void* GetFileFromArchive(EGG::Archive* pArc, const char* pName, + static void* GetFileFromArchive(EGG::Archive* pArchive, const char* pName, u32* pSize = NULL); /** - * @brief Gets a message file by name from the message archive + * @brief Gets the specified file from the message archive * - * @param pName Name of the message file + * @param pName Message file name */ static void* GetMessageResource(const char* pName); /** - * @brief Tests whether the specified file exists in the game filesystem + * @brief Tests whether a file exists at the specified path * - * @param pPath Path to the file + * @param pPath Path to examine */ bool IsExist(const char* pPath); /** - * @brief Removes a file from the user cache - * @note This is automatically called through the RPSysFile destructor. + * @brief Removes a file from the list of decompressed files + * @note RPSysFile automatically removes itself when it is destroyed. * * @param pFile File to remove */ void RemoveFromFileList(RPSysFile* pFile); /** - * @brief Loads the Kokeshi asset archive + * @brief Loads all archives and other assets with static lifetime */ - void LoadKokeshiArchive(); + void LoadStaticArchives(); + /** - * @brief Loads the archives from the current pack's static directory - * @remarks This also includes the message and font archives. + * @brief Loads the specified file and adds it to the resource cache + * @details If the file has already been cached, this function does nothing. + * + * @param pPath File path + * @param list List that the file should be moved to + * @param pHeap Heap to use for allocations */ - void LoadStaticArchives(); + void LoadCachedFile(const char* pPath, EList list, EGG::Heap* pHeap); + /** - * @brief Loads and caches the common archive of every scene + * @brief Loads all archives designated for cached access */ void LoadCacheArchives(); /** - * @brief Gets the common sound path of the current pack - * @bug This function ignores the @p bufSize parameter and instead uses - * unsafe versions of string functions. + * @brief Loads the archive containing all kokeshi assets + */ + void LoadKokeshiArchive(); + + /** + * @brief Gets the path to the common sound folder * - * @param[out] pBuffer Buffer containing resulting path - * @param bufSize Size of the buffer pointed to by @p pBuffer + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size */ - void GetStaticSoundCommonPath(char* pBuffer, u32 bufSize); + void GetStaticSoundCommonPath(char* pBuffer, u32 maxlen); + /** - * @brief Gets the local sound path of the current pack - * @bug This function ignores the @p bufSize parameter and instead uses - * unsafe versions of string functions. + * @brief Gets the path to the local sound folder * - * @param[out] pBuffer Buffer containing resulting path - * @param bufSize Size of the buffer pointed to by @p pBuffer + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size */ - void GetStaticSoundLocalPath(char* pBuffer, u32 bufSize); + void GetStaticSoundLocalPath(char* pBuffer, u32 maxlen); /** - * @brief Gets the common sound path of the specified scene - * @bug This function ignores the @p bufSize parameter and instead uses - * unsafe versions of string functions. + * @brief Gets the path to the common sound folder for the specified scene * - * @param[out] pBuffer Buffer containing resulting path - * @param bufSize Size of the buffer pointed to by @p pBuffer - * @param id Scene ID + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + * @param id Scene ID (defaults to the current scene) */ - void GetGameSoundCommonPath(char* pBuffer, u32 bufSize, s32 id = -1); + void GetGameSoundCommonPath(char* pBuffer, u32 maxlen, s32 id = -1); + /** - * @brief Gets the local sound path of the specified scene - * @bug This function ignores the @p bufSize parameter and instead uses - * unsafe versions of string functions. + * @brief Gets the path to the local sound folder for the specified scene * - * @param[out] pBuffer Buffer containing resulting path - * @param bufSize Size of the buffer pointed to by @p pBuffer - * @param id Scene ID + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + * @param id Scene ID (defaults to the current scene) */ - void GetGameSoundLocalPath(char* pBuffer, u32 bufSize, s32 id = -1); + void GetGameSoundLocalPath(char* pBuffer, u32 maxlen, s32 id = -1); + /** + * @brief Loads the local archive in the specified static asset directory + * + * @param pStaticDir Static asset directory + */ + EGG::Archive* LoadStaticLocalArchive(const char* pStaticDir) + DECOMP_DONT_INLINE; + + /** + * @brief Loads the common archive in the specified static asset directory + * + * @param pStaticDir Static asset directory + */ + EGG::Archive* LoadStaticCommonArchive(const char* pPath); + + /** + * @brief Loads the archive containing all message data + */ + void LoadMessageArchive(); + + /** + * @brief Loads the archive containing all font data + */ + void LoadFontArchive(); + + /** + * @brief Gets the archive containing all kokeshi assets + */ EGG::Archive* GetKokeshiArchive() const { return mpKokeshiArchive; } + /** + * @brief Gets the archive containing all message data + */ + EGG::Archive* GetMessageArchive() const { + return mpMessageArchive; + } + + /** + * @brief Gets the archive containing all font data + */ EGG::Archive* GetFontArchive() const { return mpFontArchive; } + /** + * @brief Gets the extra handle for opening files outside the DVD + */ void* GetMultiHandle() { return &mpMultiHandle; } private: - //! Resource cache for compressed files - nw4r::ut::List mFileCache; // at 0x4 - //! Resource cache for decompressed files - nw4r::ut::List mDecompFileCache; // at 0x10 + /** + * @brief Loads the specified file from the DVD, decompressing its contents + * if applicable + * + * @param pPath File path + * @param pHeap Heap to use for allocations + * @return Raw file contents + */ + u8* LoadCompressed(const char* pPath, EGG::Heap* pHeap); + + /** + * @brief Loads the specified file from the DVD + * + * @param pPath Path to the file + * @param pHeap Heap to use for allocations + * @param allocDir Direction of heap allocations + * @param[out] pSize Size of the specified file + */ + u8* LoadFromDVD(const char* pPath, EGG::Heap* pHeap, + EGG::DvdRipper::EAllocDirection allocDir, + s32* pSize = NULL); + + /** + * @brief Searches the specified resource list for the provided filepath + * + * @param pPath File path + * @param list Resource list + */ + RPSysFile* FindFile(const char* pPath, EList list) const; + + /** + * @brief Creates a new entry in the specified resource list + * + * @param pPath File path + * @param list Resource list + * @param size File size + * @param pData File data + * @param pHeap Heap to use for allocations + */ + void MakeFile(const char* pPath, EList list, s32 size, const void* pData, + EGG::Heap* pHeap); + + /** + * @brief Decompresses the contents of the specified data + * @details If the data is not compressed, this function returns the + * original file contents + * + * @param pData File data + * @param size Data size + * @param[out] pExpandSize The data size after decompression + * @param pHeap Heap to use for allocations + * @return Decompressed data + */ + u8* ExpandCompressed(u8* pData, s32 size, s32* pExpandSize, + EGG::Heap* pHeap) const; + +private: + //! List of scenes whose resources should be cached + static const RPSysSceneCreator::ESceneID CACHED_SCENES[]; + //! Static directory names for each pack + static const char* STATIC_DIR_NAMES[RPSysSceneCreator::EPackID_Max]; + //! Absolute path to the kokeshi asset archive + static const char* KOKESHI_ARCHIVE_PATH; + + //! Resource lists + nw4r::ut::List mResourceLists[EList_Max]; // at 0x4 //! Work buffer for building filepaths char* mpPathWork; // at 0x1C - //! Archive containing Kokeshi assets + //! Archive containing all kokeshi assets EGG::Archive* mpKokeshiArchive; // at 0x20 - //! Archive containing all message files + //! Archive containing all message data EGG::Archive* mpMessageArchive; // at 0x24 - //! Archive containing all fonts + //! Archive containing all font data EGG::Archive* mpFontArchive; // at 0x28 - //! Static common assets for this pack + //! Archive containing static common assets for this pack EGG::Archive* mpStaticCommonArchive; // at 0x2C - //! Static locale assets for this pack + //! Archive containing static locale assets for this pack EGG::Archive* mpStaticLocalArchive; // at 0x30 - //! Static layout assets for this pack + //! Archive containing static layout assets for this pack EGG::Archive* mpStaticLayoutArchive; // at 0x34 #if defined(PACK_SPORTS) //! Sports Pack Mii manager RPSportsAppMiiManager* mpAppMiiManager; // at 0x38 -#elif defined(PACK_PARTY) - //! Party Pack Mii manager - RPPartyAppMiiManager* mpAppMiiManager; // at 0x38 #endif - //! @brief Handle for opening NAND sound archives - //! @remark This seems to be for NAND titles using the Pack Project engine. + //! Extra handle for opening files outside the DVD void* mpMultiHandle; // at 0x3C }; diff --git a/include/Pack/RPSystem/RPSysSceneCreator.h b/include/Pack/RPSystem/RPSysSceneCreator.h index 124af2a32..be7028d22 100644 --- a/include/Pack/RPSystem/RPSysSceneCreator.h +++ b/include/Pack/RPSystem/RPSysSceneCreator.h @@ -123,9 +123,9 @@ class RPSysSceneCreator : public EGG::SceneCreator { EPackID_PartyPack, //!< Wii Play EPackID_HealthPack, //!< Wii Fit EPackID_MusicPack, //!< Wii Music - EPackID_AllPack, //!< Pack Project - EPackID_Max + EPackID_Max, + EPackID_AllPack = EPackID_Max, //!< Pack Project }; /** diff --git a/include/egg/core/eggArchive.h b/include/egg/core/eggArchive.h index 70441c024..af3047e42 100644 --- a/include/egg/core/eggArchive.h +++ b/include/egg/core/eggArchive.h @@ -36,7 +36,7 @@ class Archive : public Disposer { }; public: - static Archive* mount(void* pArcBinary, Heap* pHeap, int align); + static Archive* mount(void* pArcBinary, Heap* pHeap, int align = 4); static Archive* findArchive(void* pArcBinary); Archive(); diff --git a/include/egg/core/eggDvdRipper.h b/include/egg/core/eggDvdRipper.h index 34bf37d73..7e5aae774 100644 --- a/include/egg/core/eggDvdRipper.h +++ b/include/egg/core/eggDvdRipper.h @@ -10,12 +10,12 @@ class DvdRipper { public: static u8* loadToMainRAM(const char* pPath, u8* pBuffer, Heap* pHeap, - EAllocDirection allocDir, u32 offset, u32* pRead, - u32* pSize); + EAllocDirection allocDir, u32 offset = 0, + u32* pRead = NULL, u32* pSize = NULL); static u8* loadToMainRAM(DvdFile* pFile, u8* pBuffer, Heap* pHeap, - EAllocDirection allocDir, u32 offset, u32* pRead, - u32* pSize); + EAllocDirection allocDir, u32 offset = 0, + u32* pRead = NULL, u32* pSize = NULL); private: static bool sErrorRetry; diff --git a/src/Pack/RPSystem/RPSysResourceManager.cpp b/src/Pack/RPSystem/RPSysResourceManager.cpp new file mode 100644 index 000000000..66819b29d --- /dev/null +++ b/src/Pack/RPSystem/RPSysResourceManager.cpp @@ -0,0 +1,637 @@ +#include +#include +#include +#include + +#include + +#include + +RP_SINGLETON_IMPL(RPSysResourceManager); + +/** + * @brief List of scenes whose resources should be cached + */ +const RPSysSceneCreator::ESceneID RPSysResourceManager::CACHED_SCENES[] = { + RPSysSceneCreator::ESceneID_RPSysPlayerSelectScene, + RPSysSceneCreator::ESceneID_RPSysNunchukScene, + +#if defined(PACK_SPORTS) + RPSysSceneCreator::ESceneID_RPBsbScene, + RPSysSceneCreator::ESceneID_RPBowScene, + RPSysSceneCreator::ESceneID_RPGolScene, + RPSysSceneCreator::ESceneID_RPTnsScene, + RPSysSceneCreator::ESceneID_RPBoxScene, + RPSysSceneCreator::ESceneID_RPSportsTitleScene, + RPSysSceneCreator::ESceneID_RPSportsMenuScene, + RPSysSceneCreator::ESceneID_RPSportsTrainingMenuScene, + RPSysSceneCreator::ESceneID_RPSportsPhysicalMenuScene, + RPSysSceneCreator::ESceneID_RPSportsPhysicalPreviewScene, + RPSysSceneCreator::ESceneID_RPSportsPhysicalResultScene, + RPSysSceneCreator::ESceneID_RPGolSelectScene, +#elif defined(PACK_PARTY) + RPSysSceneCreator::ESceneID_RPFshScene, + RPSysSceneCreator::ESceneID_RPHkyScene, + RPSysSceneCreator::ESceneID_RPDucScene, + RPSysSceneCreator::ESceneID_RPPnpScene, + RPSysSceneCreator::ESceneID_RPBilScene, + RPSysSceneCreator::ESceneID_RPCowScene, + RPSysSceneCreator::ESceneID_RPWlyScene, + RPSysSceneCreator::ESceneID_RPTnkScene, + RPSysSceneCreator::ESceneID_RPBomScene, + RPSysSceneCreator::ESceneID_RPPartyTitleScene, + RPSysSceneCreator::ESceneID_RPPartyMiiLoadScene, + RPSysSceneCreator::ESceneID_RPPartyMenuScene, +#endif +}; + +/** + * @brief Static directory names for each pack + */ +// clang-format off +const char* RPSysResourceManager::STATIC_DIR_NAMES[RPSysSceneCreator::EPackID_Max] = { + "SportsStatic/", // EPackID_SportsPack + "PartyStatic/", // EPackID_PartyPack + "HealthStatic/", // EPackID_HealthPack + "MusicStatic/", // EPackID_MusicPack +}; +// clang-format on + +/** + * @brief Absolute path to the kokeshi asset archive + */ +const char* RPSysResourceManager::KOKESHI_ARCHIVE_PATH = + "Common/Kokeshi/common.carc"; + +/** + * @brief Constructor + */ +RPSysResourceManager::RPSysResourceManager() { + NW4R_UT_LIST_INIT(mResourceLists[EList_FileCache], RPSysFile); + NW4R_UT_LIST_INIT(mResourceLists[EList_FileList], RPSysFile); + + mpPathWork = new char[RPSysFile::PATH_MAX]; +} + +/** + * @brief Destructor + */ +RPSysResourceManager::~RPSysResourceManager() {} + +/** + * @brief Gets the path to the common asset folder for the specified scene + * + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + * @param id Scene ID (defaults to the current scene) + */ +void RPSysResourceManager::GetGameCommonPath(char* pBuffer, u32 /* maxlen */, + s32 id) { + RPSysSceneCreator* pSceneCreator = RP_GET_INSTANCE(RPSysSceneCreator); + + std::strcpy(pBuffer, "Common/"); + std::strcat(pBuffer, pSceneCreator->getResDirName(id)); +} + +/** + * @brief Loads the common asset archive for the specified scene + * + * @param id Scene ID (defaults to the current scene) + * @param pHeap Heap to use for allocations (defaults to the current heap) + */ +EGG::Archive* RPSysResourceManager::LoadGameCommonArchive(s32 id, + EGG::Heap* pHeap) { + + instance()->GetGameCommonPath(instance()->mpPathWork, RPSysFile::PATH_MAX, + id); + + std::strcat(instance()->mpPathWork, "common.carc"); + + if (pHeap == NULL) { + pHeap = EGG::Heap::getCurrentHeap(); + } + + void* pArcBinary = + instance()->LoadCompressed(instance()->mpPathWork, pHeap); + + return EGG::Archive::mount(pArcBinary, pHeap); +} + +/** + * @brief Gets the path to the local asset folder for the specified scene + * + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + * @param id Scene ID (defaults to the current scene) + */ +void RPSysResourceManager::GetGameLocalPath(char* pBuffer, u32 /* maxlen */, + s32 id) { + RPSysSceneCreator* pSceneCreator = RP_GET_INSTANCE(RPSysSceneCreator); + RPSysProjectLocal* pProjectLocal = RP_GET_INSTANCE(RPSysProjectLocal); + + pBuffer[0] = '\0'; + pProjectLocal->appendLocalDirectory(pBuffer); + + std::strcat(pBuffer, pSceneCreator->getResDirName(id)); +} + +/** + * @brief Loads the local asset archive for the specified scene + * + * @param id Scene ID (defaults to the current scene) + * @param pHeap Heap to use for allocations (defaults to the current heap) + */ +EGG::Archive* RPSysResourceManager::LoadGameLocalArchive(s32 id, + EGG::Heap* pHeap) { + instance()->GetGameLocalPath(instance()->mpPathWork, RPSysFile::PATH_MAX, + id); + + std::strcat(instance()->mpPathWork, "local.carc"); + + if (pHeap == NULL) { + pHeap = EGG::Heap::getCurrentHeap(); + } + + void* pArcBinary = + instance()->LoadCompressed(instance()->mpPathWork, pHeap); + + return EGG::Archive::mount(pArcBinary, pHeap); +} + +/** + * @brief Gets the path to the stage asset folder for the specified scene + * + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + * @param id Scene ID (defaults to the current scene) + */ +void RPSysResourceManager::GetGameStagePath(char* pBuffer, u32 /* maxlen */, + s32 id) { + RPSysSceneCreator* pSceneCreator = RP_GET_INSTANCE(RPSysSceneCreator); + + std::strcpy(pBuffer, "Stage/"); + std::strcat(pBuffer, pSceneCreator->getResDirName(id)); +} + +/** + * @brief Loads the specified archive from the current scene's stage assets + * + * @param pName Archive name + */ +EGG::Archive* RPSysResourceManager::LoadGameStageArchive(const char* pName) { + instance()->GetGameStagePath(instance()->mpPathWork, RPSysFile::PATH_MAX); + std::strcat(instance()->mpPathWork, pName); + + EGG::Heap* pHeap = EGG::Heap::getCurrentHeap(); + + void* pArcBinary = + instance()->LoadCompressed(instance()->mpPathWork, pHeap); + + return EGG::Archive::mount(pArcBinary, pHeap); +} + +/** + * @brief Gets the specified file from the provided archive + * + * @param pArchive Archive containing the file + * @param pName File name + * @param[out] pSize Size of the specified file + */ +void* RPSysResourceManager::GetFileFromArchive(EGG::Archive* pArchive, + const char* pName, u32* pSize) { + + EGG::Archive::FileInfo fileInfo; + void* pFile = pArchive->getFile(pName, &fileInfo); + + if (pSize != NULL) { + *pSize = fileInfo.getLength(); + } + + return pFile; +} + +/** + * @brief Gets the specified file from the message archive + * + * @param pName Message file name + */ +void* RPSysResourceManager::GetMessageResource(const char* pName) { + return GetFileFromArchive(instance()->GetMessageArchive(), pName); +} + +/** + * @brief Tests whether a file exists at the specified path + * + * @param pPath Path to examine + */ +bool RPSysResourceManager::IsExist(const char* pPath) { + EGG::DvdFile f; + return f.open(pPath, GetMultiHandle()); +} + +/** + * @brief Removes a file from the list of decompressed files + * @note RPSysFile automatically removes itself when it is destroyed. + * + * @param pFile File to remove + */ +void RPSysResourceManager::RemoveFromFileList(RPSysFile* pFile) { + nw4r::ut::List_Remove(&mResourceLists[EList_FileList], pFile); +} + +/** + * @brief Loads all archives and other assets with static lifetime + */ +void RPSysResourceManager::LoadStaticArchives() { + RPSysProjectLocal* pProjectLocal = RP_GET_INSTANCE(RPSysProjectLocal); + EGG::Heap* pResHeap = RP_GET_INSTANCE(RPSysSystem)->getResourceHeap(); + + mpStaticCommonArchive = + LoadStaticCommonArchive(STATIC_DIR_NAMES[pProjectLocal->getPack()]); + + mpStaticLocalArchive = + LoadStaticLocalArchive(STATIC_DIR_NAMES[pProjectLocal->getPack()]); + +#if defined(PACK_SPORTS) + mpAppMiiManager = new (pResHeap) RPSportsAppMiiManager(pResHeap); + mpAppMiiManager->LoadResource(); +#endif + + LoadMessageArchive(); + LoadFontArchive(); + + RPSysKokeshiManager* pKokeshiManager = RP_GET_INSTANCE(RPSysKokeshiManager); +#if defined(PACK_SPORTS) + pKokeshiManager->SetBodyManager(new (pResHeap) RPSportsBodyManager()); +#elif defined(PACK_PARTY) + pKokeshiManager->SetBodyManager(new (pResHeap) RPPartyBodyManager()); +#endif + + RP_GET_INSTANCE(RPSysFontManager)->LoadResFonts(); +} + +/** + * @brief Loads the specified file and adds it to the resource cache + * @details If the file has already been cached, this function does nothing. + * + * @param pPath File path + * @param list List that the file should be moved to + * @param pHeap Heap to use for allocations + */ +void RPSysResourceManager::LoadCachedFile(const char* pPath, EList list, + EGG::Heap* pHeap) { + RPSysFile* pFile = FindFile(pPath, EList_FileCache); + if (pFile != NULL) { + return; + } + + s32 fileSize = 0; + u8* pFileData = + LoadFromDVD(pPath, pHeap, EGG::DvdRipper::ALLOC_DIR_TAIL, &fileSize); + + DCFlushRange(pFileData, fileSize); + MakeFile(pPath, list, fileSize, pFileData, pHeap); +} + +/** + * @brief Loads all archives designated for cached access + */ +void RPSysResourceManager::LoadCacheArchives() { + EGG::Heap* pResHeap = RP_GET_INSTANCE(RPSysSystem)->getResourceHeap(); + + for (int i = 0; i < static_cast(ARRAY_SIZE(CACHED_SCENES)); i++) { + GetGameCommonPath(instance()->mpPathWork, RPSysFile::PATH_MAX, + CACHED_SCENES[i]); + + std::strcat(instance()->mpPathWork, "common.carc"); + LoadCachedFile(instance()->mpPathWork, EList_FileCache, pResHeap); + + // Local archives in Wii Play are small enough to also cache +#if defined(PACK_PARTY) + GetGameLocalPath(instance()->mpPathWork, RPSysFile::PATH_MAX, + CACHED_SCENES[i]); + + std::strcat(instance()->mpPathWork, "local.carc"); + LoadCachedFile(instance()->mpPathWork, EList_FileCache, pResHeap); +#endif + } +} + +/** + * @brief Loads the archive containing all kokeshi assets + */ +void RPSysResourceManager::LoadKokeshiArchive() { + EGG::Heap* pResHeap = RP_GET_INSTANCE(RPSysSystem)->getResourceHeap(); + + std::strcpy(instance()->mpPathWork, KOKESHI_ARCHIVE_PATH); + + void* pArcBinary = + instance()->LoadCompressed(instance()->mpPathWork, pResHeap); + + mpKokeshiArchive = EGG::Archive::mount(pArcBinary, pResHeap); +} + +/** + * @brief Gets the path to the common sound folder + * + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + */ +void RPSysResourceManager::GetStaticSoundCommonPath(char* pBuffer, + u32 /* maxlen */) { + RPSysProjectLocal* pProjectLocal = RP_GET_INSTANCE(RPSysProjectLocal); + + std::strcpy(pBuffer, "Sound/"); + std::strcat(pBuffer, STATIC_DIR_NAMES[pProjectLocal->getPack()]); +} + +/** + * @brief Gets the path to the local sound folder + * + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + */ +void RPSysResourceManager::GetStaticSoundLocalPath(char* pBuffer, + u32 /* maxlen */) { + RPSysProjectLocal* pProjectLocal = RP_GET_INSTANCE(RPSysProjectLocal); + + std::strcpy(pBuffer, "Sound/"); + std::strcat(pBuffer, STATIC_DIR_NAMES[pProjectLocal->getPack()]); + pProjectLocal->appendLocalDirectory(pBuffer); +} + +/** + * @brief Gets the path to the common sound folder for the specified scene + * + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + * @param id Scene ID (defaults to the current scene) + */ +void RPSysResourceManager::GetGameSoundCommonPath(char* pBuffer, + u32 /* maxlen */, s32 id) { + RPSysSceneCreator* pSceneCreator = RP_GET_INSTANCE(RPSysSceneCreator); + + std::strcpy(pBuffer, "Sound/"); + std::strcat(pBuffer, pSceneCreator->getResDirName(id)); +} + +/** + * @brief Gets the path to the local sound folder for the specified scene + * + * @param[out] pBuffer Path output buffer + * @param maxlen Output buffer size + * @param id Scene ID (defaults to the current scene) + */ +void RPSysResourceManager::GetGameSoundLocalPath(char* pBuffer, + u32 /* maxlen */, s32 id) { + RPSysSceneCreator* pSceneCreator = RP_GET_INSTANCE(RPSysSceneCreator); + RPSysProjectLocal* pProjectLocal = RP_GET_INSTANCE(RPSysProjectLocal); + + std::strcpy(pBuffer, "Sound/"); + std::strcat(pBuffer, pSceneCreator->getResDirName(id)); + pProjectLocal->appendLocalDirectory(pBuffer); +} + +/** + * @brief Loads the local archive in the specified static asset directory + * + * @param pStaticDir Static asset directory + */ +EGG::Archive* +RPSysResourceManager::LoadStaticLocalArchive(const char* pStaticDir) { + RPSysSceneCreator* pSceneCreator = RP_GET_INSTANCE(RPSysSceneCreator); + RPSysProjectLocal* pProjectLocal = RP_GET_INSTANCE(RPSysProjectLocal); + + mpPathWork[0] = '\0'; + pProjectLocal->appendLocalDirectory(mpPathWork); + + std::strcat(mpPathWork, pStaticDir); + std::strcat(mpPathWork, "local.carc"); + + EGG::Heap* pResHeap = RP_GET_INSTANCE(RPSysSystem)->getResourceHeap(); + + void* pArcBinary = + instance()->LoadCompressed(instance()->mpPathWork, pResHeap); + + return EGG::Archive::mount(pArcBinary, pResHeap); +} + +/** + * @brief Loads the common archive in the specified static asset directory + * + * @param pStaticDir Static asset directory + */ +EGG::Archive* +RPSysResourceManager::LoadStaticCommonArchive(const char* pStaticDir) { + std::strcpy(mpPathWork, "Common/"); + std::strcat(mpPathWork, pStaticDir); + std::strcat(mpPathWork, "common.carc"); + + EGG::Heap* pResHeap = RP_GET_INSTANCE(RPSysSystem)->getResourceHeap(); + + void* pArcBinary = LoadCompressed(mpPathWork, pResHeap); + return EGG::Archive::mount(pArcBinary, pResHeap); +} + +DECOMP_FORCEACTIVE(RPSysResourceManager_cpp, + "effect.carc", + "local.carc"); + +/** + * @brief Loads the archive containing all message data + */ +void RPSysResourceManager::LoadMessageArchive() { + EGG::Heap* pResHeap = RP_GET_INSTANCE(RPSysSystem)->getResourceHeap(); + RPSysProjectLocal* pProjectLocal = RP_GET_INSTANCE(RPSysProjectLocal); + + instance()->mpPathWork[0] = '\0'; + pProjectLocal->appendLocalDirectory(instance()->mpPathWork); + std::strcat(instance()->mpPathWork, "Message/message.carc"); + + void* pArcBinary = + instance()->LoadCompressed(instance()->mpPathWork, pResHeap); + + mpMessageArchive = EGG::Archive::mount(pArcBinary, pResHeap); +} + +/** + * @brief Loads the archive containing all font data + */ +void RPSysResourceManager::LoadFontArchive() { + EGG::Heap* pResHeap = RP_GET_INSTANCE(RPSysSystem)->getResourceHeap(); + RPSysProjectLocal* pProjectLocal = RP_GET_INSTANCE(RPSysProjectLocal); + + instance()->mpPathWork[0] = '\0'; + pProjectLocal->appendLocalDirectory(instance()->mpPathWork); + std::strcat(instance()->mpPathWork, "Font/font.carc"); + + void* pArcBinary = + instance()->LoadCompressed(instance()->mpPathWork, pResHeap); + + mpFontArchive = EGG::Archive::mount(pArcBinary, pResHeap); +} + +/** + * @brief Loads the specified file from the DVD, decompressing its contents + * if applicable + * + * @param pPath File path + * @param pHeap Heap to use for allocations + * @return Raw file contents + */ +u8* RPSysResourceManager::LoadCompressed(const char* pPath, EGG::Heap* pHeap) { + RPSysFile* pFile = NULL; + + // See if the file has already been decompressed + pFile = FindFile(pPath, EList_FileList); + if (pFile != NULL) { + return const_cast(pFile->GetData()); + } + + s32 fileSize = 0; + pFile = FindFile(pPath, EList_FileCache); + + // If the file is waiting in the cache, decompress it + if (pFile != NULL) { + u8* pFileData = const_cast(pFile->GetData()); + fileSize = pFile->GetSize(); + + s32 expandSize = 0; + u8* pExpandData = + ExpandCompressed(pFileData, fileSize, &expandSize, pHeap); + + DCFlushRange(pExpandData, expandSize); + + MakeFile(pPath, EList_FileList, expandSize, pExpandData, pHeap); + return pExpandData; + } + // Cache miss, need to load AND decompress the file + else { + u8* pFileData = LoadFromDVD(pPath, pHeap, + EGG::DvdRipper::ALLOC_DIR_HEAD, &fileSize); + + s32 expandSize = 0; + u8* pExpandData = + ExpandCompressed(pFileData, fileSize, &expandSize, pHeap); + + DCFlushRange(pExpandData, expandSize); + + // Original compressed data is temporary memory + delete pFileData; + + MakeFile(pPath, EList_FileList, expandSize, pExpandData, pHeap); + return pExpandData; + } +} + +/** + * @brief Loads the specified file from the DVD + * + * @param pPath Path to the file + * @param pHeap Heap to use for allocations + * @param allocDir Direction of heap allocations + * @param[out] pSize Size of the specified file + */ +u8* RPSysResourceManager::LoadFromDVD(const char* pPath, EGG::Heap* pHeap, + EGG::DvdRipper::EAllocDirection allocDir, + s32* pSize) { + EGG::DvdFile f; + + if (!f.open(pPath, GetMultiHandle())) { + return NULL; + } + + s32 fileSize = ROUND_UP(f.getFileSize(), 32); + + if (pSize != NULL) { + *pSize = fileSize; + } + + int align = 32; + if (allocDir != EGG::DvdRipper::ALLOC_DIR_TAIL) { + align = -32; + } + + u8* pBuffer = new (pHeap, align) u8[fileSize]; + + if (pBuffer == NULL) { + return NULL; + } + + return EGG::DvdRipper::loadToMainRAM(&f, pBuffer, pHeap, + EGG::DvdRipper::ALLOC_DIR_HEAD); +} + +DECOMP_FORCEACTIVE(RPSysResourceManager_cpp_1, + "/", + "Effect/", + "Stage/", + "", + "Common/"); + +/** + * @brief Searches the specified resource list for the provided filepath + * + * @param pPath File path + * @param list Resource list + */ +RPSysFile* RPSysResourceManager::FindFile(const char* pPath, EList list) const { + RPSysFile* pFile = + static_cast(nw4r::ut::List_GetFirst(&mResourceLists[list])); + + while (pFile != NULL) { + if (std::strcmp(pPath, pFile->GetPath()) == 0) { + return pFile; + } + + pFile = static_cast( + nw4r::ut::List_GetNext(&mResourceLists[list], pFile)); + } + + return NULL; +} + +/** + * @brief Creates a new entry in the specified resource list + * + * @param pPath File path + * @param list Resource list + * @param size File size + * @param pData File data + * @param pHeap Heap to use for allocations + */ +void RPSysResourceManager::MakeFile(const char* pPath, EList list, s32 size, + const void* pData, EGG::Heap* pHeap) { + + RPSysFile* pFile = new (pHeap) RPSysFile(pPath, size, pData); + nw4r::ut::List_Append(&mResourceLists[list], pFile); +} + +/** + * @brief Decompresses the contents of the specified data + * @details If the data is not compressed, this function returns the + * original file contents + * + * @param pData File data + * @param size Data size + * @param[out] pExpandSize The data size after decompression + * @param pHeap Heap to use for allocations + * @return Decompressed data + */ +u8* RPSysResourceManager::ExpandCompressed(u8* pData, s32 size, + s32* pExpandSize, + EGG::Heap* pHeap) const { + u8* pExpandData = NULL; + + if (EGG::Decomp::checkCompressed(pData) != EGG::Decomp::cCompress_None) { + *pExpandSize = EGG::Decomp::getExpandSize(pData); + pExpandData = new (pHeap, 32) u8[*pExpandSize]; + EGG::Decomp::decode(pData, pExpandData); + } else { + *pExpandSize = size; + pExpandData = new (pHeap, 32) u8[*pExpandSize]; + std::memcpy(pExpandData, pData, *pExpandSize); + } + + return pExpandData; +} diff --git a/src/Pack/RPSystem/RPSysSaveDataMgr.cpp b/src/Pack/RPSystem/RPSysSaveDataMgr.cpp index ed7c64c0f..1a0f6f2b2 100644 --- a/src/Pack/RPSystem/RPSysSaveDataMgr.cpp +++ b/src/Pack/RPSystem/RPSysSaveDataMgr.cpp @@ -583,9 +583,9 @@ void RPSysSaveDataMgr::initBanner() { u8* pTplBuffer = static_cast(EGG::Heap::alloc(mBannerFileSize, 32, pHeap)); - void* pTplFile = EGG::DvdRipper::loadToMainRAM( - BANNER_ICON_FILE_NAME, pTplBuffer, pHeap, - EGG::DvdRipper::ALLOC_DIR_HEAD, 0, NULL, NULL); + void* pTplFile = + EGG::DvdRipper::loadToMainRAM(BANNER_ICON_FILE_NAME, pTplBuffer, pHeap, + EGG::DvdRipper::ALLOC_DIR_HEAD); TPLPalette* pPalette = static_cast(pTplFile); TPLBind(pPalette);