diff --git a/asm/Kyoto/DolphinCMemoryCardSys.s b/asm/Kyoto/DolphinCMemoryCardSys.s index 3baec4f8..41cb8a1d 100644 --- a/asm/Kyoto/DolphinCMemoryCardSys.s +++ b/asm/Kyoto/DolphinCMemoryCardSys.s @@ -1265,8 +1265,8 @@ lbl_8034E4EC: /* 8034E504 0034B464 38 21 00 10 */ addi r1, r1, 0x10 /* 8034E508 0034B468 4E 80 00 20 */ blr -.global SetComment__13CCardFileInfoFv -SetComment__13CCardFileInfoFv: +.global "SetComment__13CCardFileInfoFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>" +"SetComment__13CCardFileInfoFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>": /* 8034E50C 0034B46C 94 21 FF F0 */ stwu r1, -0x10(r1) /* 8034E510 0034B470 7C 08 02 A6 */ mflr r0 /* 8034E514 0034B474 38 63 00 28 */ addi r3, r3, 0x28 diff --git a/asm/MetroidPrime/CMemoryCardDriver.s b/asm/MetroidPrime/CMemoryCardDriver.s index b5dff25b..4cb1a088 100644 --- a/asm/MetroidPrime/CMemoryCardDriver.s +++ b/asm/MetroidPrime/CMemoryCardDriver.s @@ -181,8 +181,8 @@ InitializeFromGameState__13SGameFileSlotFv: /* 8024C408 00249368 38 21 00 D0 */ addi r1, r1, 0xd0 /* 8024C40C 0024936C 4E 80 00 20 */ blr -.global DoPut__13SGameFileSlotFv -DoPut__13SGameFileSlotFv: +.global DoPut__13SGameFileSlotCFR16CMemoryStreamOut +DoPut__13SGameFileSlotCFR16CMemoryStreamOut: /* 8024C410 00249370 94 21 FF F0 */ stwu r1, -0x10(r1) /* 8024C414 00249374 7C 08 02 A6 */ mflr r0 /* 8024C418 00249378 90 01 00 14 */ stw r0, 0x14(r1) @@ -376,8 +376,8 @@ lbl_8024C674: /* 8024C698 002495F8 38 21 00 10 */ addi r1, r1, 0x10 /* 8024C69C 002495FC 4E 80 00 20 */ blr -.global DoPut__11SSaveHeaderFv -DoPut__11SSaveHeaderFv: +.global DoPut__11SSaveHeaderCFR16CMemoryStreamOut +DoPut__11SSaveHeaderCFR16CMemoryStreamOut: /* 8024C6A0 00249600 94 21 FF E0 */ stwu r1, -0x20(r1) /* 8024C6A4 00249604 7C 08 02 A6 */ mflr r0 /* 8024C6A8 00249608 90 01 00 24 */ stw r0, 0x24(r1) @@ -1250,7 +1250,7 @@ InitializeFileInfo__17CMemoryCardDriverFv: /* 8024D298 0024A1F8 4B FB EE 5D */ bl "__pl__4rstlFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>PCc" /* 8024D29C 0024A1FC 7F E3 FB 78 */ mr r3, r31 /* 8024D2A0 0024A200 38 81 00 10 */ addi r4, r1, 0x10 -/* 8024D2A4 0024A204 48 10 12 69 */ bl SetComment__13CCardFileInfoFv +/* 8024D2A4 0024A204 48 10 12 69 */ bl "SetComment__13CCardFileInfoFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>" /* 8024D2A8 0024A208 38 61 00 10 */ addi r3, r1, 0x10 /* 8024D2AC 0024A20C 48 0F 08 35 */ bl "internal_dereference__Q24rstl66basic_string,Q24rstl17rmemory_allocator>Fv" /* 8024D2B0 0024A210 38 61 00 20 */ addi r3, r1, 0x20 @@ -1299,7 +1299,7 @@ InitializeFileInfo__17CMemoryCardDriverFv: /* 8024D35C 0024A2BC 7C 00 2B 78 */ or r0, r0, r5 /* 8024D360 0024A2C0 54 00 0F FE */ srwi r0, r0, 0x1f /* 8024D364 0024A2C4 98 01 00 0E */ stb r0, 0xe(r1) -/* 8024D368 0024A2C8 4B FF F3 39 */ bl DoPut__11SSaveHeaderFv +/* 8024D368 0024A2C8 4B FF F3 39 */ bl DoPut__11SSaveHeaderCFR16CMemoryStreamOut /* 8024D36C 0024A2CC 38 61 00 A0 */ addi r3, r1, 0xa0 /* 8024D370 0024A2D0 48 0F 21 49 */ bl FlushShiftRegister__13COutputStreamFv /* 8024D374 0024A2D4 38 61 00 A0 */ addi r3, r1, 0xa0 @@ -1313,7 +1313,7 @@ lbl_8024D38C: /* 8024D390 0024A2F0 28 03 00 00 */ cmplwi r3, 0 /* 8024D394 0024A2F4 41 82 00 0C */ beq lbl_8024D3A0 /* 8024D398 0024A2F8 38 81 00 A0 */ addi r4, r1, 0xa0 -/* 8024D39C 0024A2FC 4B FF F0 75 */ bl DoPut__13SGameFileSlotFv +/* 8024D39C 0024A2FC 4B FF F0 75 */ bl DoPut__13SGameFileSlotCFR16CMemoryStreamOut lbl_8024D3A0: /* 8024D3A0 0024A300 3B BD 00 08 */ addi r29, r29, 8 lbl_8024D3A4: diff --git a/include/Kyoto/CMemoryCardSys.hpp b/include/Kyoto/CMemoryCardSys.hpp index 78f8d0cc..36db87ca 100644 --- a/include/Kyoto/CMemoryCardSys.hpp +++ b/include/Kyoto/CMemoryCardSys.hpp @@ -4,6 +4,9 @@ #include "string.h" #include "types.h" +#include "Kyoto/CSimplePool.hpp" +#include "Kyoto/Streams/CMemoryStreamOut.hpp" + #include "rstl/string.hpp" // TODO: likely comes from dolphin sdk @@ -45,17 +48,29 @@ struct CardStat { }; class CCardFileInfo { - uchar pad[0x114]; + uchar pad[0xf4]; + rstl::vector xf4_saveBuffer; + rstl::vector x104_cardBuffer; public: CCardFileInfo(EMemoryCardPort port, const rstl::string& name); ~CCardFileInfo(); + void SetComment(const rstl::string& name); + void LockBannerToken(CAssetId bannerTxtr, CSimplePool& sp); + void LockIconToken(CAssetId iconTxtr, int speed, CSimplePool& sp); + ECardResult PumpCardTransfer(); ECardResult CreateFile(); ECardResult WriteFile(); ECardResult CloseFile(); + + inline CMemoryStreamOut BeginMemoryOut(uint sz) { + xf4_saveBuffer.resize(sz, '\x00'); + return CMemoryStreamOut(xf4_saveBuffer.data(), sz, CMemoryStreamOut::kOS_NotOwned, sz); + } }; +CHECK_SIZEOF(CCardFileInfo, 0x114) class CMemoryCardSys { public: diff --git a/include/Kyoto/Streams/CMemoryStreamOut.hpp b/include/Kyoto/Streams/CMemoryStreamOut.hpp new file mode 100644 index 00000000..4befd536 --- /dev/null +++ b/include/Kyoto/Streams/CMemoryStreamOut.hpp @@ -0,0 +1,17 @@ +#ifndef _CMEMORYSTREAMOUT +#define _CMEMORYSTREAMOUT + +#include "Kyoto/Streams/COutputStream.hpp" + +class CMemoryStreamOut : public COutputStream { +public: + enum EOwnerShip { + kOS_Owned, + kOS_NotOwned, + }; + + CMemoryStreamOut(uchar* buffer, size_t len, EOwnerShip ownerShip = kOS_NotOwned, int blockLen = 4096); + virtual ~CMemoryStreamOut(); +}; + +#endif // _CMEMORYSTREAMOUT diff --git a/include/Kyoto/Streams/COutputStream.hpp b/include/Kyoto/Streams/COutputStream.hpp index d851d21c..8351ee53 100644 --- a/include/Kyoto/Streams/COutputStream.hpp +++ b/include/Kyoto/Streams/COutputStream.hpp @@ -37,6 +37,16 @@ public: void WriteLong(int t) { Put(&t, sizeof(int)); } + void WriteChar(u8 c) { + FlushShiftRegister(); + if (mBufLen <= mPosition) { + DoFlush(); + } + ++mNumWrites; + *(reinterpret_cast< u8* >(mBufPtr) + mPosition) = c; + ++mPosition; + } + private: uint mPosition; uint mBufLen; @@ -63,4 +73,9 @@ inline void coutput_stream_helper(const uint& t, COutputStream& out) { out.WriteLong(t); } +template <> +inline void coutput_stream_helper(const bool& t, COutputStream& out) { + out.WriteChar(static_cast< char >(t)); +} + #endif // _COUTPUTSTREAM diff --git a/include/MetroidPrime/CMemoryCardDriver.hpp b/include/MetroidPrime/CMemoryCardDriver.hpp index 86c52ba1..e8d26b01 100644 --- a/include/MetroidPrime/CMemoryCardDriver.hpp +++ b/include/MetroidPrime/CMemoryCardDriver.hpp @@ -35,6 +35,32 @@ struct SMemoryCardFileInfo { ECardResult GetSaveDataOffset(u32& offOut) const; }; +struct SSaveHeader { + uint x0_version; + bool x4_savePresent[3]; + + SSaveHeader(); + // : x0_version(0) {} + + void DoPut(CMemoryStreamOut& out) const; /* { + out.WriteLong(x0_version); + for (int i = 0; i < 3; ++i) { + out.Put(x4_savePresent[i]); + } + }*/ +}; + +struct SGameFileSlot { + u8 x0_saveBuffer[940]; + CGameState::GameFileStateInfo x944_fileInfo; + + SGameFileSlot(); + // explicit SGameFileSlot(CMemoryInStream& in); + void InitializeFromGameState(); + void LoadGameState(u32 idx); + void DoPut(CMemoryStreamOut& w) const; // { w.Put(x0_saveBuffer, 940); } +}; + enum EState { kS_Initial = 0, kS_Ready = 1, @@ -93,17 +119,6 @@ public: enum EFileState { kFS_Unknown, kFS_NoFile, kFS_File, kFS_BadFile }; private: - struct SGameFileSlot { - u8 x0_saveBuffer[940]; - CGameState::GameFileStateInfo x944_fileInfo; - - SGameFileSlot(); - // explicit SGameFileSlot(CMemoryInStream& in); - void InitializeFromGameState(); - void LoadGameState(u32 idx); - // void DoPut(CMemoryStreamOut& w) const { w.Put(x0_saveBuffer.data(), x0_saveBuffer.size()); } - }; - EMemoryCardPort x0_cardPort; CAssetId x4_saveBanner; CAssetId x8_saveIcon0; @@ -125,8 +140,8 @@ private: public: static bool IsCardBusy(EState); static bool IsCardWriting(EState); - CMemoryCardDriver(EMemoryCardPort cardPort, CAssetId saveBanner, - CAssetId saveIcon0, CAssetId saveIcon1, bool importPersistent); + CMemoryCardDriver(EMemoryCardPort cardPort, CAssetId saveBanner, CAssetId saveIcon0, + CAssetId saveIcon1, bool importPersistent); void ClearFileInfo(); ~CMemoryCardDriver(); void Update(); diff --git a/include/dolphin/os.h b/include/dolphin/os.h index 26e5540e..72cf1584 100644 --- a/include/dolphin/os.h +++ b/include/dolphin/os.h @@ -66,6 +66,24 @@ void OSInit(); OSTime OSGetTime(); OSTick OSGetTick(); +typedef struct OSCalendarTime { + int x0_sec; // seconds after the minute [0, 61] + int x4_min; // minutes after the hour [0, 59] + int x8_hour; // hours since midnight [0, 23] + int xc_mday; // day of the month [1, 31] + int x10_mon; // month since January [0, 11] + int x14_year; // years in AD [1, ...] + int x18_wday; // days since Sunday [0, 6] + int x1c_yday; // days since January 1 [0, 365] + + int x20_msec; // milliseconds after the second [0,999] + int x24_usec; // microseconds after the millisecond [0,999] +} OSCalendarTime; + +OSTime OSCalendarTimeToTicks( OSCalendarTime* td ); +void OSTicksToCalendarTime( OSTime ticks, OSCalendarTime* td ); + + #define OS_CONSOLE_MASK 0xf0000000 #define OS_CONSOLE_RETAIL 0x00000000 #define OS_CONSOLE_DEVELOPMENT 0x10000000 diff --git a/src/MetroidPrime/CMemoryCardDriver.cpp b/src/MetroidPrime/CMemoryCardDriver.cpp index 3c0b2925..fe413e50 100644 --- a/src/MetroidPrime/CMemoryCardDriver.cpp +++ b/src/MetroidPrime/CMemoryCardDriver.cpp @@ -2,6 +2,9 @@ #include "MetroidPrime/CMain.hpp" +#include "dolphin/os.h" +#include "stdio.h" + static bool lbl_805A9118; static const char* const skSaveFileNames[2] = {"MetroidPrime A", "MetroidPrime B"}; @@ -625,7 +628,8 @@ void CMemoryCardDriver::StartFileDeleteAltTransactional() { x14_error = kE_OK; x10_state = kS_FileAltDeleteTransactional; int bidx = x194_fileIdx == 0 ? 1 : 0; - ECardResult result = CMemoryCardSys::DeleteFile(x0_cardPort, rstl::string_l(skSaveFileNames[bidx])); + ECardResult result = + CMemoryCardSys::DeleteFile(x0_cardPort, rstl::string_l(skSaveFileNames[bidx])); if (result != kCR_READY) UpdateFileAltDeleteTransactional(result); } @@ -638,7 +642,39 @@ void CMemoryCardDriver::StartCardFormat() { UpdateCardFormat(result); } -void CMemoryCardDriver::InitializeFileInfo() {} +void CMemoryCardDriver::InitializeFileInfo() { + ExportPersistentOptions(); + + OSCalendarTime time; + OSTicksToCalendarTime(OSGetTime(), &time); + + char nameBuffer[36]; + + sprintf(nameBuffer, "%02d.%02d.%02d %02d:%02d", time.x10_mon + 1, time.xc_mday, + time.x14_year % 100, time.x8_hour, time.x4_min); + + x198_fileInfo->SetComment(rstl::string_l("Metroid Prime ") + nameBuffer); + + x198_fileInfo->LockBannerToken(x4_saveBanner, *gpSimplePool); + x198_fileInfo->LockIconToken(x8_saveIcon0, 2, *gpSimplePool); + + CMemoryStreamOut w = x198_fileInfo->BeginMemoryOut(3004); + + SSaveHeader header; + for (int i = 0; i < xe4_fileSlots.capacity(); ++i) { + header.x4_savePresent[i] = !xe4_fileSlots[i].null(); + } + header.DoPut(w); + + w.Put(x30_systemData.data(), x30_systemData.size()); + + for (int i = 0; i < xe4_fileSlots.size(); ++i) { + rstl::auto_ptr< SGameFileSlot >& fileSlot = xe4_fileSlots[i]; + if (!fileSlot.null()) { + fileSlot->DoPut(w); + } + } +} void CMemoryCardDriver::ReadFinished() {}