From 0614e8cb9e09b3029cfb1cc875c2d9e3f5b8f944 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sun, 14 Jul 2024 10:04:10 -0700 Subject: [PATCH] m_Do_MemCardRWmng work --- include/JSystem/JKernel/JKRAram.h | 4 + include/d/d_com_inf_game.h | 9 ++ include/d/d_save.h | 6 +- include/dolphin/card.h | 34 +++++ include/m_Do/m_Do_MemCard.h | 2 +- include/m_Do/m_Do_MemCardRWmng.h | 10 +- include/m_Do/m_Do_dvd_thread.h | 2 +- src/m_Do/m_Do_MemCard.cpp | 2 +- src/m_Do/m_Do_MemCardRWmng.cpp | 225 +++++++++++++++++++++++++++--- 9 files changed, 265 insertions(+), 29 deletions(-) diff --git a/include/JSystem/JKernel/JKRAram.h b/include/JSystem/JKernel/JKRAram.h index 34a1b24a1..fa9b43da5 100644 --- a/include/JSystem/JKernel/JKRAram.h +++ b/include/JSystem/JKernel/JKRAram.h @@ -82,6 +82,10 @@ inline u8* JKRAramToMainRam(u32 p1, u8* p2, u32 p3, JKRExpandSwitch p4, u32 p5, return JKRAram::aramToMainRam(p1, p2, p3, p4, p5, p6, p7, p8); } +inline u8* JKRAramToMainRam(JKRAramBlock* block, u8* dst, u32 size, u32 p4 = 0, JKRExpandSwitch expandSwitch = EXPAND_SWITCH_UNKNOWN0, u32 p5 = 0, JKRHeap* heap = NULL, int p6 = -1, u32* p7 = 0) { + return JKRAram::aramToMainRam(block, dst, size, p4, expandSwitch, p5, heap, p6, p7); +} + inline JKRAramBlock *JKRMainRamToAram(u8 *buf, u32 bufSize, u32 alignedSize, JKRExpandSwitch expandSwitch, u32 fileSize, JKRHeap *heap, int id) { return JKRAram::mainRamToAram(buf, bufSize, alignedSize, expandSwitch, fileSize, heap, id); } diff --git a/include/d/d_com_inf_game.h b/include/d/d_com_inf_game.h index 8dfc72b9d..a2de44ccd 100644 --- a/include/d/d_com_inf_game.h +++ b/include/d/d_com_inf_game.h @@ -504,6 +504,7 @@ class dComIfG_play_c { JKRAramBlock* getPictureBoxData(int i) { return mPictureBoxData[i]; } void setPictureBoxData(JKRAramBlock* aramBlock, int i) { mPictureBoxData[i] = aramBlock; } + bool isPictureFlag(u8 i) { return mPictureFlag & (1 << i); } void offPictureFlag(u8 i) { u8 mask = (1 << i); mPictureFlag &= ~mask; @@ -1199,6 +1200,10 @@ inline void dComIfGs_setTurnRestart(const cXyz& i_pos, s16 i_angle, s8 i_roomNo, g_dComIfG_gameInfo.save.getTurnRestart().set(i_pos, i_angle, i_roomNo, i_param, i_shipPos, i_shipAngle, i_hasShip); } +inline u8 dComIfGs_getDataNum() { + g_dComIfG_gameInfo.save.getDataNum(); +} + inline u8 dComIfGs_getPlayerPriestFlag() { return g_dComIfG_gameInfo.save.getPlayer().getPriest().getFlag(); } @@ -2617,6 +2622,10 @@ inline void dComIfGp_setPictureBoxData(JKRAramBlock* aramBlock, int i) { g_dComIfG_gameInfo.play.setPictureBoxData(aramBlock, i); } +inline bool dComIfGp_isPictureFlag(u8 i) { + g_dComIfG_gameInfo.play.isPictureFlag(i); +} + inline void dComIfGp_offPictureFlag(u8 i) { g_dComIfG_gameInfo.play.offPictureFlag(i); } diff --git a/include/d/d_save.h b/include/d/d_save.h index 995b39cb2..ebd957586 100644 --- a/include/d/d_save.h +++ b/include/d/d_save.h @@ -813,11 +813,11 @@ class dSv_info_c { void removeZone(int zoneNo) { mZone[zoneNo].reset(); } void initDan(s8 i_stage) { mDan.init(i_stage); } - void getDataNum() {} + u8 getDataNum() { return mDataNum; } void getMemCardCheckID() {} void getNewFile() {} void getNoFile() {} - void setDataNum(u8) {} + void setDataNum(u8 num) { mDataNum = num; } void setMemCardCheckID(u64) {} void setNewFile(u8) {} void setNoFile(u8) {} @@ -838,7 +838,7 @@ class dSv_info_c { /* 0x1128 */ dSv_restart_c mRestart; /* 0x1158 */ dSv_event_c mTmp; /* 0x1258 */ dSv_turnRestart_c mTurnRestart; - /* 0x1290 */ u8 field_0x1290; + /* 0x1290 */ u8 mDataNum; /* 0x1291 */ u8 field_0x1291; /* 0x1292 */ u8 field_0x1292; /* 0x1298 */ s64 field_0x1298; diff --git a/include/dolphin/card.h b/include/dolphin/card.h index ccb066730..14cc3a2cc 100644 --- a/include/dolphin/card.h +++ b/include/dolphin/card.h @@ -16,6 +16,36 @@ struct CARDFileInfo { /* 0x12 */ u16 __padding; }; +struct CARDStat { + u8 fileName[32]; + u32 dataLength; + u32 lastModified; + u8 gameCode[4]; + u8 company[2]; + + u8 bannerFmt; + u32 iconAddr; + u16 iconFormat; + u16 iconSpeed; + u32 commentAddr; + + u32 offsetBanner; + u32 offsetBannerTlut; + u32 offsetIcon[8]; + u32 offsetIconTlut; + u32 offsetData; +}; + +#define CARDGetBannerFormat(stat) ((stat)->bannerFmt & 0x03) +#define CARDGetIconAnim(stat) ((stat)->bannerFmt & 0x04) +#define CARDGetIconFormat(stat, n) ((stat)->iconFormat >> (2 * (n)) & 0x03) +#define CARDGetIconSpeed(stat, n) ((stat)->iconSpeed >> (2 * (n)) & 0x03) + +#define CARDSetBannerFormat(stat, v) ((stat)->bannerFmt = (u8)(((stat)->bannerFmt & ~0x03) | (v))) +#define CARDSetIconAnim(stat, v) ((stat)->bannerFmt = (u8)(((stat)->bannerFmt & ~0x04) | (v))) +#define CARDSetIconFormat(stat, n, v) ((stat)->iconFormat = (u16)(((stat)->iconFormat & ~(0x03 << (2 * (n)))) | ((v) << (2 * (n))))) +#define CARDSetIconSpeed(stat, n, v) ((stat)->iconSpeed = (u16)(((stat)->iconSpeed & ~(0x03 << (2 * (n)))) | ((v) << (2 * (n))))) + enum { CARD_ERROR_UNLOCKED = 1, CARD_ERROR_READY = 0, @@ -38,6 +68,8 @@ enum { void CARDInit(); BOOL CARDProbe(s32); +s32 CARDGetStatus(s32, s32, CARDStat*); +s32 CARDSetStatus(s32, s32, CARDStat*); s32 CARDOpen(s32, const char*, CARDFileInfo*); s32 CARDClose(CARDFileInfo*); s32 CARDCreate(s32, const char*, s32, CARDFileInfo*); @@ -47,6 +79,8 @@ s32 CARDUnmount(s32); s32 CARDMount(s32, void*, void*); s32 CARDCheck(s32); s32 CARDFreeBlocks(s32, s32*, s32*); +s32 CARDRead(CARDFileInfo*, void*, s32, s32); +s32 CARDWrite(CARDFileInfo*, const void*, s32, s32); #ifdef __cplusplus } diff --git a/include/m_Do/m_Do_MemCard.h b/include/m_Do/m_Do_MemCard.h index f5551a5ca..ec3fd7afb 100644 --- a/include/m_Do/m_Do_MemCard.h +++ b/include/m_Do/m_Do_MemCard.h @@ -49,7 +49,7 @@ class mDoMemCd_Ctrl_c { /* 0x0000 */ u8 mData[0x1650]; /* 0x1650 */ s32 mCardCommand; - /* 0x1654 */ s32 mCardState; + /* 0x1654 */ u8* mCardBuf; /* 0x1658 */ u8 mCardSlot; /* 0x1659 */ u8 field_0x1659; /* 0x165A */ u8 field_0x165A; diff --git a/include/m_Do/m_Do_MemCardRWmng.h b/include/m_Do/m_Do_MemCardRWmng.h index 99bd1881b..098c3a4d2 100644 --- a/include/m_Do/m_Do_MemCardRWmng.h +++ b/include/m_Do/m_Do_MemCardRWmng.h @@ -13,13 +13,13 @@ s32 mDoMemCdRWm_Restore2(CARDFileInfo*); #endif void mDoMemCdRWm_BuildHeader(mDoMemCdRWm_HeaderData*); void mDoMemCdRWm_SetCardStat(CARDFileInfo*); -void mDoMemCdRWm_CheckCardStat(CARDFileInfo*); -void mDoMemCdRWm_CalcCheckSum(void*, u32); -void mDoMemCdRWm_CalcCheckSumPictData(void*, u32); +BOOL mDoMemCdRWm_CheckCardStat(CARDFileInfo*); +u32 mDoMemCdRWm_CalcCheckSum(void*, u32); +u16 mDoMemCdRWm_CalcCheckSumPictData(void*, u32); BOOL mDoMemCdRWm_TestCheckSumPictData(void*); void mDoMemCdRWm_SetCheckSumPictData(u8*); -void mDoMemCdRWm_CalcCheckSumGameData(void*, u32); -void mDoMemCdRWm_TestCheckSumGameData(void*); +unsigned long long mDoMemCdRWm_CalcCheckSumGameData(void*, u32); +BOOL mDoMemCdRWm_TestCheckSumGameData(void*); void mDoMemCdRWm_SetCheckSumGameData(u8*, u8); #endif /* M_DO_M_DO_MEMCARDRWMNG_H */ diff --git a/include/m_Do/m_Do_dvd_thread.h b/include/m_Do/m_Do_dvd_thread.h index dd6b0d7fc..10bfcc7c1 100644 --- a/include/m_Do/m_Do_dvd_thread.h +++ b/include/m_Do/m_Do_dvd_thread.h @@ -14,7 +14,7 @@ typedef void* (*mDoDvdThd_callback_func)(void*); class mDoDvdThd_command_c : public node_class { public: - /* 0x0C */ bool mIsDone; + /* 0x0C */ volatile bool mIsDone; /* 0x10 vtable*/ public: virtual ~mDoDvdThd_command_c(); diff --git a/src/m_Do/m_Do_MemCard.cpp b/src/m_Do/m_Do_MemCard.cpp index 0ef55ba00..d5845dfe3 100644 --- a/src/m_Do/m_Do_MemCard.cpp +++ b/src/m_Do/m_Do_MemCard.cpp @@ -25,7 +25,7 @@ mDoMemCd_Ctrl_c::mDoMemCd_Ctrl_c() { void mDoMemCd_Ctrl_c::ThdInit() { CARDInit(); mCardCommand = 0; - mCardState = 0; + mCardBuf = NULL; field_0x1659 = 0; field_0x165A = 2; field_0x1660 = CARD_NO_COMMAND; diff --git a/src/m_Do/m_Do_MemCardRWmng.cpp b/src/m_Do/m_Do_MemCardRWmng.cpp index e4105b40b..e85ec9271 100644 --- a/src/m_Do/m_Do_MemCardRWmng.cpp +++ b/src/m_Do/m_Do_MemCardRWmng.cpp @@ -4,11 +4,117 @@ // #include "m_Do/m_Do_MemCardRWmng.h" -#include "dolphin/types.h" +#include "m_Do/m_Do_MemCard.h" +#include "m_Do/m_Do_dvd_thread.h" +#include "d/d_com_inf_game.h" +#include "JSystem/JKernel/JKRAram.h" +#include "JSystem/JUtility/JUTTexture.h" +#include "dolphin/card.h" +#include "dolphin/os/OS.h" + +#include +#include + +struct mDoMemCdRWm_HeaderData +{ + /* 0x0000 */ u8 banner[0x0e00]; + /* 0x0e00 */ u8 icon[0x0200]; + /* 0x1000 */ u8 field_0x1000[0x0c00]; + /* 0x1c00 */ char comment[32]; + /* 0x1c20 */ char info[32]; +}; + +struct card_savedata +{ + u32 saveCount; + u32 field_0x04; + u8 data[0x1ff4]; + u32 csum; +}; + +struct card_pictdata +{ + u8 data[0x1ffe]; + u16 csum; +}; + +struct card_gamedata +{ + u8 data[0x768]; + unsigned long long csum; +}; + +static u8 sTmpBuf[0x2000]; +static u32 sSaveCount; /* 80019940-80019CE8 .text mDoMemCdRWm_Store__FP12CARDFileInfoPvUl */ -s32 mDoMemCdRWm_Store(CARDFileInfo*, void*, u32) { +s32 mDoMemCdRWm_Store(CARDFileInfo* card, void* data, u32 size) { /* Nonmatching */ + s32 ret; + mDoMemCdRWm_BuildHeader((mDoMemCdRWm_HeaderData*)sTmpBuf); + ret = CARDWrite(card, sTmpBuf, 0x2000, 0x0000); + if (ret != CARD_ERROR_READY) return ret; + + if (!mDoMemCdRWm_CheckCardStat(card)) { + memset(sTmpBuf, 0, 0x2000); + ret = CARDWrite(card, sTmpBuf, 0x2000, 0x2000); + if (ret != CARD_ERROR_READY) return ret; + ret = CARDWrite(card, sTmpBuf, 0x2000, 0x4000); + if (ret != CARD_ERROR_READY) return ret; + sSaveCount = 0; + } + + memset(sTmpBuf, 0, 0x2000); + card_savedata* save = (card_savedata*)sTmpBuf; + save->field_0x04 = 0; + memcpy(save->data, data, size); + save->saveCount = ++sSaveCount; + s32 csum = mDoMemCdRWm_CalcCheckSum(data, 0x1FFC); + save->csum = csum; + + ret = CARDWrite(card, sTmpBuf, 0x2000, 0x2000); + if (ret != CARD_ERROR_READY) return ret; + ret = CARDRead(card, sTmpBuf, 0x2000, 0x2000); + if (ret != CARD_ERROR_READY) return ret; + if (mDoMemCdRWm_CalcCheckSum(sTmpBuf, 0x1FFC) != csum) return ret; + + ret = CARDWrite(card, sTmpBuf, 0x2000, 0x4000); + if (ret != CARD_ERROR_READY) return ret; + ret = CARDRead(card, sTmpBuf, 0x2000, 0x4000); + if (ret != CARD_ERROR_READY) return ret; + if (mDoMemCdRWm_CalcCheckSum(sTmpBuf, 0x1FFC) != csum) return ret; + + if (g_mDoMemCd_control.mCardBuf != NULL) { + u32 slot = g_mDoMemCd_control.field_0x1659; + if (slot < 3) { + u8* picData = g_mDoMemCd_control.mCardBuf; + for (u32 i = 0; i < 3; i++, picData += 0x2000) { + u32 cardOffset = (slot * 3 + 3 + i) * 0x2000; + ret = CARDWrite(card, picData, 0x2000, cardOffset); + if (ret != CARD_ERROR_READY) return ret; + ret = CARDRead(card, picData, 0x2000, cardOffset); + if (ret != CARD_ERROR_READY) return ret; + if (!mDoMemCdRWm_TestCheckSumPictData(picData)) return CARD_ERROR_READY; + ret = CARD_ERROR_READY; + } + } + } else { + u8 dataNum = dComIfGs_getDataNum(); + for (s32 i = 0; i < 3; i++) { + if (dComIfGp_isPictureFlag(i)) { + memset(sTmpBuf, 0, 0x2000); + JKRAramToMainRam(dComIfGp_getPictureBoxData(i), sTmpBuf, 0x2000); + u32 cardOffset = (dataNum * 3 + 3 + i) * 0x2000; + ret = CARDWrite(card, sTmpBuf, 0x2000, cardOffset); + if (ret != CARD_ERROR_READY) return ret; + ret = CARDRead(card, sTmpBuf, 0x2000, cardOffset); + if (ret != CARD_ERROR_READY) return ret; + } + } + } + + mDoMemCdRWm_SetCardStat(card); + return ret; } /* 80019CE8-80019F4C .text mDoMemCdRWm_Restore__FP12CARDFileInfoPvUl */ @@ -23,51 +129,134 @@ s32 mDoMemCdRWm_Restore2(CARDFileInfo*) { #endif /* 80019F4C-8001A0A8 .text mDoMemCdRWm_BuildHeader__FP22mDoMemCdRWm_HeaderData */ -void mDoMemCdRWm_BuildHeader(mDoMemCdRWm_HeaderData*) { - /* Nonmatching */ +void mDoMemCdRWm_BuildHeader(mDoMemCdRWm_HeaderData* header) { + snprintf(header->comment, sizeof(header->comment), "Zelda: The Wind Waker"); + OSTime time = OSGetTime(); + OSCalendarTime cal; + OSTicksToCalendarTime(time, &cal); + snprintf(header->info, sizeof(header->info), "%d/%d Save Data", cal.month + 1, cal.day_of_month); + mDoDvdThd_mountArchive_c* cmd = mDoDvdThd_mountArchive_c::create("/res/CardIcon/cardicon.arc", 0, NULL); + while (!cmd->sync()) ; + JKRArchive* arc = cmd->getArchive(); + ResTIMG* banner = (ResTIMG*)arc->getResource("ipl_banner.bti"); + ResTIMG* icon = (ResTIMG*)arc->getResource("ipl_icon1.bti"); + memcpy(header->banner, ((char*)banner) + banner->imageOffset, 0xc00 + banner->numColors * 2); + memcpy(header->icon, ((char*)icon) + icon->imageOffset, 0x400 + icon->numColors * 2); + arc->unmount(); + delete cmd; } /* 8001A0A8-8001A1EC .text mDoMemCdRWm_SetCardStat__FP12CARDFileInfo */ -void mDoMemCdRWm_SetCardStat(CARDFileInfo*) { - /* Nonmatching */ +void mDoMemCdRWm_SetCardStat(CARDFileInfo* card) { + CARDStat stat; + CARDGetStatus(g_mDoMemCd_control.mCardSlot, card->fileNo, &stat); + stat.iconAddr = 0; + stat.commentAddr = offsetof(mDoMemCdRWm_HeaderData, comment); + CARDSetBannerFormat(&stat, 1); + CARDSetIconAnim(&stat, 0); + CARDSetIconFormat(&stat, 0, 1); + CARDSetIconFormat(&stat, 1, 0); + CARDSetIconFormat(&stat, 2, 0); + CARDSetIconFormat(&stat, 3, 0); + CARDSetIconFormat(&stat, 4, 0); + CARDSetIconFormat(&stat, 5, 0); + CARDSetIconFormat(&stat, 6, 0); + CARDSetIconFormat(&stat, 7, 0); + CARDSetIconSpeed(&stat, 0, 3); + CARDSetIconSpeed(&stat, 1, 0); + CARDSetIconSpeed(&stat, 2, 0); + CARDSetIconSpeed(&stat, 3, 0); + CARDSetIconSpeed(&stat, 4, 0); + CARDSetIconSpeed(&stat, 5, 0); + CARDSetIconSpeed(&stat, 6, 0); + CARDSetIconSpeed(&stat, 7, 0); + CARDSetStatus(g_mDoMemCd_control.mCardSlot, card->fileNo, &stat);; } /* 8001A1EC-8001A2F0 .text mDoMemCdRWm_CheckCardStat__FP12CARDFileInfo */ -void mDoMemCdRWm_CheckCardStat(CARDFileInfo*) { - /* Nonmatching */ +BOOL mDoMemCdRWm_CheckCardStat(CARDFileInfo* card) { + CARDStat stat; + CARDGetStatus(g_mDoMemCd_control.mCardSlot, card->fileNo, &stat); + if (!(stat.iconAddr == 0 && + stat.commentAddr == 0x1C00 && + CARDGetBannerFormat(&stat) == 1 && + CARDGetIconAnim(&stat) == 0 && + CARDGetIconFormat(&stat, 0) == 1 && + CARDGetIconFormat(&stat, 1) == 0 && + CARDGetIconFormat(&stat, 2) == 0 && + CARDGetIconFormat(&stat, 3) == 0 && + CARDGetIconFormat(&stat, 4) == 0 && + CARDGetIconFormat(&stat, 5) == 0 && + CARDGetIconFormat(&stat, 6) == 0 && + CARDGetIconFormat(&stat, 7) == 0 && + CARDGetIconSpeed(&stat, 0) == 3 && + CARDGetIconSpeed(&stat, 1) == 0 && + CARDGetIconSpeed(&stat, 2) == 0 && + CARDGetIconSpeed(&stat, 3) == 0 && + CARDGetIconSpeed(&stat, 4) == 0 && + CARDGetIconSpeed(&stat, 5) == 0 && + CARDGetIconSpeed(&stat, 6) == 0 && + CARDGetIconSpeed(&stat, 7) == 0)) + return false; + return true; } /* 8001A2F0-8001A330 .text mDoMemCdRWm_CalcCheckSum__FPvUl */ -void mDoMemCdRWm_CalcCheckSum(void*, u32) { +u32 mDoMemCdRWm_CalcCheckSum(void* p_, u32 size) { /* Nonmatching */ + u16 c0 = 0, c1 = 0; + u16* p = (u16*)p_; + for (int i = 0; i < size >> 1; i++, p++) { + c0 += *p; + c1 += ~*p; + } + return (c0 << 16) | c1; } /* 8001A330-8001A358 .text mDoMemCdRWm_CalcCheckSumPictData__FPvUl */ -void mDoMemCdRWm_CalcCheckSumPictData(void*, u32) { - /* Nonmatching */ +u16 mDoMemCdRWm_CalcCheckSumPictData(void* p, u32 size) { + u16 csum = 0; + for (int i = 0; i < size; i++) { + u8 v = ((u8*)p)[i]; + csum += v; + } + return csum; } /* 8001A358-8001A39C .text mDoMemCdRWm_TestCheckSumPictData__FPv */ -BOOL mDoMemCdRWm_TestCheckSumPictData(void*) { +BOOL mDoMemCdRWm_TestCheckSumPictData(void* p) { /* Nonmatching */ + card_pictdata* save = (card_pictdata*)p; + return save->csum == mDoMemCdRWm_CalcCheckSumPictData(save->data, sizeof(save->data)); } /* 8001A39C-8001A3D0 .text mDoMemCdRWm_SetCheckSumPictData__FPUc */ -void mDoMemCdRWm_SetCheckSumPictData(u8*) { - /* Nonmatching */ +void mDoMemCdRWm_SetCheckSumPictData(u8* p) { + card_pictdata* save = (card_pictdata*)p; + save->csum = mDoMemCdRWm_CalcCheckSumPictData(save->data, sizeof(save->data)); } /* 8001A3D0-8001A408 .text mDoMemCdRWm_CalcCheckSumGameData__FPvUl */ -void mDoMemCdRWm_CalcCheckSumGameData(void*, u32) { +unsigned long long mDoMemCdRWm_CalcCheckSumGameData(void* p, u32 size) { /* Nonmatching */ + u32 c0 = 0, c1 = 0; + for (int i = 0; i < size; i++) { + u8 v = ((u8*)p)[i]; + c0 += v; + c1 += ~v; + } + return ((unsigned long long)c0 << 32) | c1; } /* 8001A408-8001A454 .text mDoMemCdRWm_TestCheckSumGameData__FPv */ -void mDoMemCdRWm_TestCheckSumGameData(void*) { +BOOL mDoMemCdRWm_TestCheckSumGameData(void *p) { /* Nonmatching */ + card_gamedata* save = (card_gamedata*)p; + return mDoMemCdRWm_CalcCheckSumGameData(save->data, sizeof(save->data)) == save->csum; } /* 8001A454-8001A498 .text mDoMemCdRWm_SetCheckSumGameData__FPUcUc */ -void mDoMemCdRWm_SetCheckSumGameData(u8*, u8) { - /* Nonmatching */ +void mDoMemCdRWm_SetCheckSumGameData(u8* p, u8 slot) { + card_gamedata* save = &((card_gamedata*)p)[slot]; + save->csum = mDoMemCdRWm_CalcCheckSumGameData(save->data, sizeof(save->data)); }