diff --git a/config/RSPE01_01/symbols.txt b/config/RSPE01_01/symbols.txt index 8739da4d..9ca1934f 100644 --- a/config/RSPE01_01/symbols.txt +++ b/config/RSPE01_01/symbols.txt @@ -7230,11 +7230,11 @@ fn_8018E59C = .text:0x8018E59C; // type:function size:0x10 fn_8018E5AC = .text:0x8018E5AC; // type:function size:0x10 fn_8018E5BC = .text:0x8018E5BC; // type:function size:0xD4 fn_8018E690 = .text:0x8018E690; // type:function size:0x60 -fn_8018E6F0 = .text:0x8018E6F0; // type:function size:0xC84 -fn_8018F374 = .text:0x8018F374; // type:function size:0x132C -fn_801906A0 = .text:0x801906A0; // type:function size:0x5C -fn_801906FC = .text:0x801906FC; // type:function size:0x48 -fn_80190744 = .text:0x80190744; // type:function size:0x50 +saveData__11RPSysPlayerFRC14RPSysPlayerArg = .text:0x8018E6F0; // type:function size:0xC84 +loadData__11RPSysPlayerFRC14RPSysPlayerArg = .text:0x8018F374; // type:function size:0x132C +setAvatar__11RPSysPlayerFScUs11RFLCreateID = .text:0x801906A0; // type:function size:0x5C +reset__11RPSysPlayerFv = .text:0x801906FC; // type:function size:0x48 +__ct__11RPSysPlayerFv = .text:0x80190744; // type:function size:0x50 __dt__18IRPSysHostIOSocketFv = .text:0x80190794; // type:function size:0x40 __ct__18IRPSysHostIOSocketFv = .text:0x801907D4; // type:function size:0x10 __ct__18IRPSysHostIOSocketFPCce = .text:0x801907E4; // type:function size:0x5C diff --git a/configure.py b/configure.py index a75f47cd..6995d778 100755 --- a/configure.py +++ b/configure.py @@ -1172,7 +1172,7 @@ def MatchingFor(*versions): Object(Matching, "Pack/RPSystem/RPPartySystemData.cpp"), Object(Matching, "Pack/RPSystem/RPPartyPlayerData.cpp"), Object(NonMatching, "Pack/RPSystem/RPSysPlayerMgr.cpp"), - Object(NonMatching, "Pack/RPSystem/RPSysPlayer.cpp"), + Object(Matching, "Pack/RPSystem/RPSysPlayer.cpp"), ], }, { diff --git a/include/Pack/RPSystem/RPSysPlayer.h b/include/Pack/RPSystem/RPSysPlayer.h index f7c1077d..0dc61277 100644 --- a/include/Pack/RPSystem/RPSysPlayer.h +++ b/include/Pack/RPSystem/RPSysPlayer.h @@ -2,32 +2,114 @@ #define RP_SYSTEM_PLAYER_H #include -#include +#include +#include #include //! @addtogroup rp_system //! @{ +/** + * @brief Player function parameter set + */ +struct RPSysPlayerArg { + //! Sports Pack player data for official database Miis + RPSportsPlayerData* pSportsPlayerData; // at 0x0 + //! Sports Pack player data for temporary storage (guest/controller miis) + RPSportsPlayerData** ppTempSportsPlayerData; // at 0x4 + + //! Party Pack player data for official database Miis + RPPartyPlayerData* pPartyPlayerData; // at 0x8 + //! Party Pack player data for temporary storage (guest/controller miis) + RPPartyPlayerData** ppTempPartyPlayerData; // at 0xC +}; + /** * @brief Player object */ class RPSysPlayer { public: + /** + * @brief Constructor + */ + RPSysPlayer(); + + /** + * @brief Destructor + */ + ~RPSysPlayer() { + // @bug Memory leak +#if defined(BUG_FIX) + delete mpSportsPlayerData; + mpSportsPlayerData = NULL; + + delete mpPartyPlayerData; + mpPartyPlayerData = NULL; +#endif + } + + /** + * @brief Resets the data to a default state + */ + void reset(); + + /** + * @brief Sets the Mii avatar associated with this player + * + * @param dataSrc Mii data source + * @param index Mii database index + * @param createID Mii create ID + */ + void setAvatar(s8 dataSrc, u16 index, RFLCreateID createID); + + /** + * @brief Loads this player's data + * + * @param rArg Parameter set + */ + void loadData(const RPSysPlayerArg& rArg); + + /** + * @brief Saves this player's data + * + * @param rArg Parameter set + */ + void saveData(const RPSysPlayerArg& rArg); + + /** + * @brief Gets the RFL data source where this player avatar can be found + * @details If the data source was never configured, this value will be -1. + */ s8 getDataSource() const { return mDataSource; } + /** + * @brief Gets the database index where this player avatar can be found + */ u16 getIndex() const { return mIndex; } private: - u8 mChannel; // at 0x0 - s8 mDataSource; // at 0x1 - u16 mIndex; // at 0x2 + //! Controller channel + u8 mChannel; // at 0x0 + + //! Mii data source + s8 mDataSource; // at 0x1 + //! Mii database index + u16 mIndex; // at 0x2 + //! Mii create ID RFLCreateID mCreateID; // at 0x4 - // . . . + + //! Player data list index + s32 mPlayerDataIndex; // at 0xC + + //! Sports Pack player data + RPSportsPlayerData* mpSportsPlayerData; // at 0x10 + //! Party Pack player datya + RPPartyPlayerData* mpPartyPlayerData; // at 0x14 }; //! @} diff --git a/src/Pack/RPSystem/RPSysPlayer.cpp b/src/Pack/RPSystem/RPSysPlayer.cpp new file mode 100644 index 00000000..f544b940 --- /dev/null +++ b/src/Pack/RPSystem/RPSysPlayer.cpp @@ -0,0 +1,179 @@ +#include + +#include + +namespace { + +/** + * @brief Tests whether two given RFL create IDs are equivalent + * + * @param rLhs Left-hand side ID + * @param rRhs Right-hand side ID + */ +bool IsSameCreateID(const RFLCreateID& rLhs, const RFLCreateID& rRhs) { + for (u32 i = 0; i < RFL_CREATEID_LEN; i++) { + if (rLhs.data[i] != rRhs.data[i]) { + return false; + } + } + + return true; +} + +} // namespace + +/** + * @brief Constructor + */ +RPSysPlayer::RPSysPlayer() : mpSportsPlayerData(NULL), mpPartyPlayerData(NULL) { +#if defined(PACK_SPORTS) + mpSportsPlayerData = new RPSportsPlayerData(); +#elif defined(PACK_PARTY) + mpPartyPlayerData = new RPPartyPlayerData(); +#endif +} + +/** + * @brief Resets the data to a default state + */ +void RPSysPlayer::reset() { + mChannel = WPAD_CHAN0; + mDataSource = -1; + mIndex = -1; + mPlayerDataIndex = -1; + + for (int i = 0; i < RFL_CREATEID_LEN; i++) { + mCreateID.data[i] = 0; + } + +#if defined(PACK_SPORTS) + mpSportsPlayerData->reset(); +#elif defined(PACK_PARTY) + mpPartyPlayerData->reset(); +#endif +} + +/** + * @brief Sets the Mii avatar associated with this player + * + * @param dataSrc Mii data source + * @param index Mii database index + * @param createID Mii create ID + */ +void RPSysPlayer::setAvatar(s8 dataSrc, u16 index, RFLCreateID createID) { + mDataSource = dataSrc; + mIndex = index; + mCreateID = createID; +} + +/** + * @brief Loads this player's data + * + * @param rArg Parameter set + */ +void RPSysPlayer::loadData(const RPSysPlayerArg& rArg) { + mPlayerDataIndex = mIndex; + + if (mDataSource == RFLDataSource_Official && mIndex < RFL_DB_CHAR_MAX) { + RPSysSaveDataMgr* pSaveDataMgr = RP_GET_INSTANCE(RPSysSaveDataMgr); + + if (mpSportsPlayerData != NULL) { + *mpSportsPlayerData = + pSaveDataMgr->getSportsPlayerData(mPlayerDataIndex); + } + + if (mpPartyPlayerData != NULL) { + *mpPartyPlayerData = + pSaveDataMgr->getPartyPlayerData(mPlayerDataIndex); + } + + } else if (mDataSource == RFLDataSource_Default && + mIndex < RFL_DEFAULT_CHAR_MAX) { + + if (mpSportsPlayerData != NULL && rArg.pSportsPlayerData != NULL) { + *mpSportsPlayerData = rArg.pSportsPlayerData[mPlayerDataIndex]; + } + + if (mpPartyPlayerData != NULL && rArg.pPartyPlayerData != NULL) { + *mpPartyPlayerData = rArg.pPartyPlayerData[mPlayerDataIndex]; + } + + } else if (mDataSource >= RFLDataSource_Controller1 && + mDataSource <= RFLDataSource_Controller4 && + mIndex < RFL_CTRL_CHAR_MAX) { + + u32 ctrlIndex = mDataSource - RFLDataSource_Controller1; + + if (mpSportsPlayerData != NULL && rArg.ppTempSportsPlayerData != NULL) { + *mpSportsPlayerData = + rArg.ppTempSportsPlayerData[ctrlIndex][mPlayerDataIndex]; + } + + if (mpPartyPlayerData != NULL && rArg.ppTempPartyPlayerData != NULL) { + *mpPartyPlayerData = + rArg.ppTempPartyPlayerData[ctrlIndex][mPlayerDataIndex]; + } + } + + RFLCreateID expected; + mpSportsPlayerData->getCreateID(&expected); + + if (!IsSameCreateID(mCreateID, expected)) { + mpSportsPlayerData->reset(); + mpSportsPlayerData->setCreateID(&mCreateID); + } +} + +/** + * @brief Saves this player's data + * + * @param rArg Parameter set + */ +void RPSysPlayer::saveData(const RPSysPlayerArg& rArg) { + if (mPlayerDataIndex < 0) { + return; + } + + if (mDataSource == RFLDataSource_Official && + mPlayerDataIndex < RFL_DB_CHAR_MAX) { + + RPSysSaveDataMgr* pSaveDataMgr = RP_GET_INSTANCE(RPSysSaveDataMgr); + + if (mpSportsPlayerData != NULL) { + pSaveDataMgr->setSportsPlayerData(*mpSportsPlayerData, + mPlayerDataIndex); + } + + if (mpPartyPlayerData != NULL) { + pSaveDataMgr->setPartyPlayerData(*mpPartyPlayerData, + mPlayerDataIndex); + } + + } else if (mDataSource == RFLDataSource_Default && + mPlayerDataIndex < RFL_DEFAULT_CHAR_MAX) { + + if (mpSportsPlayerData != NULL && rArg.pSportsPlayerData != NULL) { + rArg.pSportsPlayerData[mPlayerDataIndex] = *mpSportsPlayerData; + } + + if (mpPartyPlayerData != NULL && rArg.pPartyPlayerData != NULL) { + rArg.pPartyPlayerData[mPlayerDataIndex] = *mpPartyPlayerData; + } + + } else if (mDataSource >= RFLDataSource_Controller1 && + mDataSource <= RFLDataSource_Controller4 && + mPlayerDataIndex < RFL_CTRL_CHAR_MAX) { + + u32 ctrlIndex = mDataSource - RFLDataSource_Controller1; + + if (mpSportsPlayerData != NULL && rArg.ppTempSportsPlayerData != NULL) { + rArg.ppTempSportsPlayerData[ctrlIndex][mPlayerDataIndex] = + *mpSportsPlayerData; + } + + if (mpPartyPlayerData != NULL && rArg.ppTempPartyPlayerData != NULL) { + rArg.ppTempPartyPlayerData[ctrlIndex][mPlayerDataIndex] = + *mpPartyPlayerData; + } + } +}