diff --git a/include/dolphin/dolphin.h b/include/dolphin/dolphin.h index f9b4cd4a5..7aeeb07e5 100644 --- a/include/dolphin/dolphin.h +++ b/include/dolphin/dolphin.h @@ -241,6 +241,8 @@ void VIWaitForRetrace(); #define CARD_MAX_FILE 127 #define CARD_ICON_MAX 8 +typedef void (*CARDCallback)(s32 chan, s32 result); + typedef struct CARDFileInfo { /*0x00*/ s32 chan; @@ -256,6 +258,12 @@ typedef struct CARDFileInfo #define CARD_ATTR_GLOBAL 0x20u #define CARD_ATTR_COMPANY 0x40u +#define CARD_STAT_SPEED_END 0 +#define CARD_STAT_SPEED_FAST 1 +#define CARD_STAT_SPEED_MIDDLE 2 +#define CARD_STAT_SPEED_SLOW 3 +#define CARD_STAT_SPEED_MASK 3 + #define CARD_RESULT_UNLOCKED 1 #define CARD_RESULT_READY 0 #define CARD_RESULT_BUSY -1 @@ -274,13 +282,61 @@ typedef struct CARDFileInfo #define CARD_RESULT_CANCELED -14 #define CARD_RESULT_FATAL_ERROR -128 +#define CARD_ICON_WIDTH 32 +#define CARD_ICON_HEIGHT 32 + +#define CARD_BANNER_WIDTH 96 +#define CARD_BANNER_HEIGHT 32 + +#define CARD_STAT_ICON_NONE 0 +#define CARD_STAT_ICON_C8 1 +#define CARD_STAT_ICON_RGB5A3 2 +#define CARD_STAT_ICON_MASK 3 + +#define CARD_STAT_BANNER_NONE 0 +#define CARD_STAT_BANNER_C8 1 +#define CARD_STAT_BANNER_RGB5A3 2 +#define CARD_STAT_BANNER_MASK 3 + +#define CARD_ENCODE_ANSI 0 +#define CARD_ENCODE_SJIS 1 + +#define CARD_STAT_ANIM_LOOP 0x00 +#define CARD_STAT_ANIM_BOUNCE 0x04 +#define CARD_STAT_ANIM_MASK 0x04 + +#define CARDGetDirCheck(dir) ((CARDDirCheck*)&(dir)[CARD_MAX_FILE]) +#define CARDGetBannerFormat(stat) (((stat)->bannerFormat) & CARD_STAT_BANNER_MASK) +#define CARDGetIconAnim(stat) (((stat)->bannerFormat) & CARD_STAT_ANIM_MASK) +#define CARDGetIconFormat(stat, n) (((stat)->iconFormat >> (2 * (n))) & CARD_STAT_ICON_MASK) +#define CARDGetIconSpeed(stat, n) (((stat)->iconSpeed >> (2 * (n))) & CARD_STAT_SPEED_MASK) +#define CARDSetBannerFormat(stat, f) \ + ((stat)->bannerFormat = (u8)(((stat)->bannerFormat & ~CARD_STAT_BANNER_MASK) | (f))) +#define CARDSetIconAnim(stat, f) \ + ((stat)->bannerFormat = (u8)(((stat)->bannerFormat & ~CARD_STAT_ANIM_MASK) | (f))) +#define CARDSetIconFormat(stat, n, f) \ + ((stat)->iconFormat = \ + (u16)(((stat)->iconFormat & ~(CARD_STAT_ICON_MASK << (2 * (n)))) | ((f) << (2 * (n))))) +#define CARDSetIconSpeed(stat, n, f) \ + ((stat)->iconSpeed = \ + (u16)(((stat)->iconSpeed & ~(CARD_STAT_SPEED_MASK << (2 * (n)))) | ((f) << (2 * (n))))) +#define CARDSetIconAddress(stat, addr) ((stat)->iconAddr = (u32)(addr)) +#define CARDSetCommentAddress(stat, addr) ((stat)->commentAddr = (u32)(addr)) +#define CARDGetFileNo(fileInfo) ((fileInfo)->fileNo) + // CARDBios.h void CARDInit(void); +s32 CARDGetResultCode(s32 chan); s32 CARDFreeBlocks(s32 chan, s32* byteNotUsed, s32* filesNotUsed); s32 CARDGetEncoding(s32 chan, u16* encode); s32 CARDGetSectorSize(s32 chan, u32* size); +// CARDCreate +s32 CARDCreate(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo); +// CARDDelete +s32 CARDDelete(s32 chan, const char* fileName); // CARDMount.h s32 CARDProbeEx(s32 chan, s32* memSize, s32* sectorSize); +s32 CARDMount(s32 chan, void* workArea, CARDCallback detachCallback); s32 CARDUnmount(s32 chan); // CARDCheck.h s32 CARDCheckEx(s32 chan, s32* xferBytes); @@ -303,15 +359,23 @@ typedef struct CARDStat /*0x64*/ u32 offsetIconTlut; /*0x68*/ u32 offsetData; } CARDStat; +s32 CARDGetStatus(s32 chan, s32 fileNo, CARDStat* stat); s32 CARDSetStatus(s32 chan, s32 fileNo, struct CARDStat* stat); // CARDRead.h +s32 CARDReadAsync(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset, CARDCallback callback); s32 CARDRead(struct CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset); +// CARDWrite +s32 CARDWriteAsync(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset, CARDCallback callback); // CARDOpen.h s32 CARDFastOpen(s32 chan, s32 fileNo, CARDFileInfo* fileInfo); s32 CARDOpen(s32 chan, char* fileName, CARDFileInfo* fileInfo); s32 CARDClose(CARDFileInfo* fileInfo); // CARDNet s32 CARDSetAttributes(s32 chan, s32 fileNo, u8 attr); +// CARDFormat +s32 CARDFormat(s32 chan); +// CARDRdwr +s32 CARDGetXferredBytes(s32 chan); #ifdef __cplusplus } diff --git a/src/SB/Core/gc/isavegame.cpp b/src/SB/Core/gc/isavegame.cpp index 251d97873..78cde8584 100644 --- a/src/SB/Core/gc/isavegame.cpp +++ b/src/SB/Core/gc/isavegame.cpp @@ -1,6 +1,9 @@ #include "isavegame.h" +#include "zGlobals.h" + #include "xMemMgr.h" +#include "xSnd.h" #include "iFile.h" #include "iSystem.h" @@ -14,18 +17,52 @@ // Not 100% on what this does or if it's correctly defined for all cases. Seems to be used for allocation alignment #define ALIGN_THING(x, n) (n + x - 1 & -x) -// WIP +// name is a total guess for now +struct st_ISG_TPL_TEX +{ + struct UnkIn + { + U32 unk_0; + U32 unk_4; + void* unk_8; + U32 unk_c; + U32 unk_10[4]; + U8 unk_20; + U8 unk_21; + U8 unk_22; + U8 unk_23; + }; + struct UnkOut + { + U8 unk_0; + U8 unk_1; + U8 unk_2; + U8 unk_3; + U32 unk_4; + void* unk_8; + }; + + UnkIn* unk_0; + UnkOut* unk_4; +}; +// WIP. Looks like some sort of header for a file with embedded texture information. struct st_ISG_TPL_TEXPALETTE { + U32 magic; + U32 count; + st_ISG_TPL_TEX* unk_8; }; +// .bss +static char cardwork[2][0xa000]; + // .sbss static volatile S32 g_isginit; static st_ISG_TPL_TEXPALETTE* g_rawicon; static st_ISG_TPL_TEXPALETTE* g_rawbanr; -static S32 g_iconsize; -static S32 g_banrsize; -static S8 isMounted; +static U32 g_iconsize; +static U32 g_banrsize; +static U8 isMounted; // .data static st_ISGSESSION g_isgdata_MAIN = { 0 }; @@ -90,6 +127,20 @@ char* iSGMakeName(en_NAMEGEN_TYPE type, const char* base, S32 idx) return use_buf; } +static const char* __deadstripped() +{ + return "Slot %c\0" + "Memory Card Slot %c\0" + "Nintendo GameCube Memory Card in Slot %c\0" + "Nintendo GameCube%s Memory Card in Slot %c\0" + "^\0" + "Nintendo GameCube%s Memory Card\0" + "is damaged and cannot be used\0" + "unsupprted sector size\0" + "is formatted for another market\0" + "encountered unexpected error (%d)"; +} + st_ISGSESSION* iSGSessionBegin(void* cltdata, void (*chgfunc)(void*, en_CHGCODE), S32 monitor) { iTRCDisk::CheckDVDAndResetState(); @@ -158,7 +209,7 @@ S32 iSGTgtPhysSlotIdx(st_ISGSESSION* isgdata, S32 tidx) static S32 iSG_mc_exists(S32 slot); static S32 iSG_mc_isGCcard(st_ISG_MEMCARD_DATA* mcdata, int* param2, int* param3); -static S32 iSG_mc_format(st_ISG_MEMCARD_DATA*, int, int*); +static S32 iSG_mc_format(st_ISG_MEMCARD_DATA*, S32, S32* canRecover); S32 iSGTgtFormat(st_ISGSESSION* isgdata, S32 tgtidx, S32 async, S32* canRecover) { S32 slot = 0; @@ -459,7 +510,7 @@ S32 iSGFileSize(st_ISGSESSION* isgdata, const char* fname) ret = iSG_get_fsize(data, fname); if (ret >= 0) { - ret -= iSG_cubeicon_size(data->unk_4, data->sectorSize); + ret -= iSG_cubeicon_size(data->chan, data->sectorSize); if (ret < 0) { ret = -1; @@ -575,11 +626,11 @@ S32 iSGSetupGameDir(st_ISGSESSION* isgdata, const char* dname, S32 force_iconfix static char* iSG_bfr_icondata(char* param1, CARDStat* stat, char* param3, int param4); static S32 iSG_mc_fopen(st_ISG_MEMCARD_DATA*, const char*, S32, en_ISG_IOMODE, en_ASYNC_OPERR*); -static void iSG_mc_fclose(st_ISG_MEMCARD_DATA*); -static void iSG_mc_fclose(st_ISG_MEMCARD_DATA*, CARDStat*); -static S32 iSG_mc_fdel(st_ISG_MEMCARD_DATA*, const char*); -static S32 iSG_mc_fwrite(st_ISG_MEMCARD_DATA*, char*, int); -static S32 iSG_upd_icostat(CARDStat*, CARDStat*); +static S32 iSG_mc_fclose(st_ISG_MEMCARD_DATA*); +static S32 iSG_mc_fclose(st_ISG_MEMCARD_DATA*, CARDStat*); +static S32 iSG_mc_fdel(st_ISG_MEMCARD_DATA* mcdata, const char* fname); +static S32 iSG_mc_fwrite(st_ISG_MEMCARD_DATA* mcdata, char* buf, S32 bufsize); +static void iSG_upd_icostat(CARDStat*, CARDStat*); static void iSG_timestamp(CARDStat*); S32 iSGSaveFile(st_ISGSESSION* isgdata, const char* fname, char* data, S32 n, S32 async, char* arg5) { @@ -636,12 +687,12 @@ S32 iSGSaveFile(st_ISGSESSION* isgdata, const char* fname, char* data, S32 n, S3 if (writeret != 0) { - iSG_upd_icostat(&statA, &mcdata->unk_20); - iSG_timestamp(&mcdata->unk_20); + iSG_upd_icostat(&statA, &mcdata->fstat); + iSG_timestamp(&mcdata->fstat); s32 result; do { - result = CARDSetStatus(mcdata->unk_4, mcdata->unk_c.fileNo, &mcdata->unk_20); + result = CARDSetStatus(mcdata->chan, mcdata->finfo.fileNo, &mcdata->fstat); } while (result == CARD_RESULT_BUSY); if (result != CARD_RESULT_READY) @@ -655,7 +706,7 @@ S32 iSGSaveFile(st_ISGSESSION* isgdata, const char* fname, char* data, S32 n, S3 s32 result; do { - result = CARDSetAttributes(mcdata->unk_4, mcdata->unk_c.fileNo, CARD_ATTR_PUBLIC); + result = CARDSetAttributes(mcdata->chan, mcdata->finfo.fileNo, CARD_ATTR_PUBLIC); } while (result == CARD_RESULT_BUSY); } @@ -700,9 +751,13 @@ S32 iSGLoadFile(st_ISGSESSION* isgdata, const char* fname, char* databuf, S32 as static S32 iSG_mc_fread(st_ISG_MEMCARD_DATA* mcdata, char*, S32, S32); S32 iSGReadLeader(st_ISGSESSION* isgdata, const char* fname, char* databuf, S32 numbytes, S32 async) { + void* alloc = NULL; + S32 allocsize; + char* readbuf; + S32 bufsize; + en_ASYNC_OPERR operr = ISG_OPERR_NONE; S32 readret = 0; - void* alloc = NULL; if (isgdata->slot < 0) { isgdata->unk_26c = ISG_OPSTAT_FAILURE; @@ -719,28 +774,27 @@ S32 iSGReadLeader(st_ISGSESSION* isgdata, const char* fname, char* databuf, S32 } iTRCDisk::CheckDVDAndResetState(); - S32 iconsize = iSG_cubeicon_size(data->unk_4, data->sectorSize); - U32 sign = (S32)databuf >> 0x1f; - // /x + (n-1) & -x is the same as Round x up to next n - S32 nearest200 = -data->sectorSize & 0x1ff + data->sectorSize; - // FIXME: I think the code is supposed to check if there is enough room at the end of the existing databuf allocation to use - // and only allocate if not. - void* readbuf; - if (((sign * 0x20 | (int)databuf * 0x8000000 + sign >> 0x1b) != sign) || - (sign = numbytes, readbuf = databuf, numbytes != (numbytes / nearest200) * nearest200)) - { - sign = numbytes + 0x1ffU & 0xfffffe00; - S32 __n = sign + 0x1f; - alloc = (void*)xMemPushTemp(__n); - readbuf = alloc; - memset(alloc, 0, __n); - readbuf = (char*)((int)alloc + 0x1fU & 0xffffffe0); + S32 iconsize = iSG_cubeicon_size(data->chan, data->sectorSize); + S32 sectorsize200 = ALIGN_THING(data->sectorSize, 0x200); + if ((S32)databuf % 32 != 0 || numbytes - ((numbytes / sectorsize200) * sectorsize200) != 0) + { + bufsize = (iconsize + 0x1ff & ~0x1ff); + S32 allocsize = bufsize + 0x1f; + alloc = xMemPushTemp(allocsize); + memset(alloc, 0, allocsize); + readbuf = (char*)((U32)alloc + 0x1f & ~0x1f); } + else + { + readbuf = databuf; + bufsize = numbytes; + } + iTRCDisk::CheckDVDAndResetState(); if (iSG_mc_fopen(data, fname, -1, ISG_IOMODE_READ, &operr) != 0) { - readret = (bool)iSG_mc_fread(data, (char*)readbuf, numbytes, iconsize); + readret = (bool)iSG_mc_fread(data, (char*)readbuf, bufsize, iconsize); iSG_mc_fclose(data); } @@ -780,7 +834,30 @@ en_ASYNC_OPSTAT iSGPollStatus(st_ISGSESSION* isgdata, en_ASYNC_OPCODE* curop, S3 en_ASYNC_OPERR iSGOpError(st_ISGSESSION* isgdata, char* errmsg) { - static char errmsgs[0x15][0x4] = { 0 }; + static char* errmsgs[0x16] = { + "No current error", + "No operation in async queue", + "Too many async ops queued simultaneously", + "Init Failed", + "Unable to access Save Game Directory", + "Access Error - no card ?!? (eg yanked out)", + "Access Error - no room on card (file handles free bytes, etc)", + "Access Error - card is damaged or something bad", + "Access Error - file being loaded appears to be corrupt (I-Level)", + "Access Error - general problem", + "Save Error - Not enough free space to save file", + "Save Error - during initalization (async queue)", + "Save Error - during write", + "Save Error - opening file", + "Load Error - during initalization (async queue)", + "Load Error - during read", + "Load Error - opening file", + "Target problem (general error)", + "Target Error - media removed or changed", + "Target Error - Not ready for I/O (unformatted?)", + "Operation encountered unknown error", + NULL + }; en_ASYNC_OPERR err; if (errmsg == NULL) @@ -899,7 +976,7 @@ static S32 iSG_mc_tryRepair(st_ISG_MEMCARD_DATA* mcdata) { do { - result = CARDCheckEx(mcdata->unk_4, &xferBytes); + result = CARDCheckEx(mcdata->chan, &xferBytes); } while (result == CARD_RESULT_BUSY); if (result == CARD_RESULT_READY) @@ -940,7 +1017,7 @@ static S32 iSG_mc_isformatted(st_ISG_MEMCARD_DATA* mcdata) { do { - result = CARDCheckEx(mcdata->unk_4, &xferBytes); + result = CARDCheckEx(mcdata->chan, &xferBytes); } while (result == CARD_RESULT_BUSY); if (result == CARD_RESULT_READY) @@ -991,7 +1068,7 @@ static S32 iSG_mc_isGCcard(st_ISG_MEMCARD_DATA* mcdata, int* param2, int* param3 do { - result = CARDProbeEx(mcdata->unk_4, &memSize, §orSize); + result = CARDProbeEx(mcdata->chan, &memSize, §orSize); } while (result == CARD_RESULT_BUSY); if (result == CARD_RESULT_READY) @@ -1003,7 +1080,7 @@ static S32 iSG_mc_isGCcard(st_ISG_MEMCARD_DATA* mcdata, int* param2, int* param3 { do { - result = CARDCheckEx(mcdata->unk_4, &xferBytes); + result = CARDCheckEx(mcdata->chan, &xferBytes); } while (result == CARD_RESULT_BUSY); if (result == CARD_RESULT_READY) @@ -1043,7 +1120,7 @@ static S32 iSG_mc_isGCcard(st_ISG_MEMCARD_DATA* mcdata, int* param2, int* param3 { do { - result = CARDGetEncoding(mcdata->unk_4, &encoding); + result = CARDGetEncoding(mcdata->chan, &encoding); } while (result == CARD_RESULT_BUSY); if (result == CARD_RESULT_READY && encoding && param2) @@ -1073,13 +1150,13 @@ static S32 iSG_isSpaceForFile(st_ISG_MEMCARD_DATA* mcdata, S32 param2, const cha { return 0; } - len = iSG_cubeicon_size(mcdata->unk_4, mcdata->sectorSize); + len = iSG_cubeicon_size(mcdata->chan, mcdata->sectorSize); len = len + param2; len = ALIGN_THING(mcdata->sectorSize, len); do { - result = CARDFreeBlocks(mcdata->unk_4, &byteNotUsed, &filesNotUsed); + result = CARDFreeBlocks(mcdata->chan, &byteNotUsed, &filesNotUsed); } while (result == CARD_RESULT_BUSY); if (result == CARD_RESULT_READY) @@ -1131,7 +1208,7 @@ static S32 iSG_mc_settgt(st_ISG_MEMCARD_DATA* mcdata, S32 slot) if (iSG_mc_mount(slot)) { mcdata->unk_0 = 1; - mcdata->unk_4 = slot; + mcdata->chan = slot; iSG_mc_tryRepair(mcdata); CARDGetSectorSize(slot, (u32*)&mcdata->sectorSize); @@ -1152,8 +1229,8 @@ static S32 iSG_get_finfo(st_ISG_MEMCARD_DATA* mcdata, const char* dpath) if (iSG_mc_fopen(mcdata, dpath, -1, ISG_IOMODE_READ, &operr)) { rc = 1; - memcpy(&mcdata->unk_b0, &mcdata->unk_20, sizeof(CARDStat)); - memcpy(&mcdata->unk_9c, &mcdata->unk_c, sizeof(CARDFileInfo)); + memcpy(&mcdata->unk_b0, &mcdata->fstat, sizeof(CARDStat)); + memcpy(&mcdata->unk_9c, &mcdata->finfo, sizeof(CARDFileInfo)); iSG_mc_fclose(mcdata); } @@ -1216,7 +1293,7 @@ static S32 iSG_fileKosher(st_ISG_MEMCARD_DATA* mcdata, const char* param2, int p return -1; } - S32 ret = iSG_curKosher(&mcdata->unk_20, &mcdata->unk_c); + S32 ret = iSG_curKosher(&mcdata->fstat, &mcdata->finfo); iSG_mc_fclose(mcdata); if (ret == 0) @@ -1335,15 +1412,16 @@ static S32 iSG_chk_icondata() return 1; } -void iSG_tpl_unpack(st_ISG_TPL_TEXPALETTE*); +static S32 iSG_tpl_unpack(st_ISG_TPL_TEXPALETTE*); +static S32 iSG_bnr_unpack(st_ISG_TPL_TEXPALETTE*); static S32 iSG_load_icondata() { - g_rawicon = (st_ISG_TPL_TEXPALETTE*)iFileLoad("/SBGCIcon.tpl", NULL, (U32*)g_iconsize); - g_rawbanr = (st_ISG_TPL_TEXPALETTE*)iFileLoad("/SBGCBanner.tpl", NULL, (U32*)g_banrsize); + g_rawicon = (st_ISG_TPL_TEXPALETTE*)iFileLoad("/SBGCIcon.tpl", NULL, &g_iconsize); + g_rawbanr = (st_ISG_TPL_TEXPALETTE*)iFileLoad("/SBGCBanner.tpl", NULL, &g_banrsize); iSG_tpl_unpack(g_rawicon); - iSG_tpl_unpack(g_rawbanr); + iSG_bnr_unpack(g_rawbanr); - return g_rawicon && g_iconsize && g_rawbanr && g_banrsize ? 1 : 0; + return g_rawicon && (S32)g_iconsize && g_rawbanr && (S32)g_banrsize ? 1 : 0; } static void iSG_discard_icondata() @@ -1356,22 +1434,12 @@ static void iSG_discard_icondata() g_banrsize = 0; } -struct TEX -{ - struct UnkStruct - { - U32 unk_0; - U32 unk_4; - void* unk_8; - }; - UnkStruct* unk_0; -}; -static TEX* iSG_tpl_TEXGet(st_ISG_TPL_TEXPALETTE*, unsigned int); +static st_ISG_TPL_TEX* iSG_tpl_TEXGet(st_ISG_TPL_TEXPALETTE*, unsigned int); static char* iSG_bfr_icondata(char* param1, CARDStat* stat, char* param3, int param4) { IconData data = { 0 }; static st_ISG_TPL_TEXPALETTE* ico_pal; - static TEX* ico_desc; + static st_ISG_TPL_TEX* ico_desc; static U32 i = 0; sprintf(data.footer, "SPONGEBOB:WHENROBOTSATTACK::RyanNeilDan"); @@ -1397,10 +1465,508 @@ static char* iSG_bfr_icondata(char* param1, CARDStat* stat, char* param3, int pa memcpy(param1, &data, sizeof(data)); - S32 t = ALIGN_THING(param4, 0x1ff); + S32 t = ALIGN_THING(param4, 0x200); return param1 + (t + (sizeof(IconData) - 1) & -t); } +static void iSG_upd_icostat(CARDStat*, CARDStat* stat) +{ + CARDSetCommentAddress(stat, 0); + CARDSetBannerFormat(stat, CARD_STAT_BANNER_RGB5A3); + CARDSetIconAddress(stat, 0x40); + CARDSetIconAnim(stat, CARD_STAT_ANIM_LOOP); + + for (S32 i = 0; i < CARD_ICON_MAX; ++i) + { + CARDSetIconFormat(stat, i, CARD_STAT_BANNER_RGB5A3); + CARDSetIconSpeed(stat, i, CARD_STAT_SPEED_MIDDLE); + } +} + +static S32 iSG_tpl_unpack(st_ISG_TPL_TEXPALETTE* tpl) +{ + if (tpl->magic != 0x20af30) + { + return 0; + } + + tpl->unk_8 = (st_ISG_TPL_TEX*)((U32)tpl + (U32)tpl->unk_8); + for (S32 i = 0; i < tpl->count; ++i) + { + st_ISG_TPL_TEX* x = &tpl->unk_8[i]; + if (x->unk_0 != NULL) + { + x->unk_0 = (st_ISG_TPL_TEX::UnkIn*)((U32)tpl + (U32)x->unk_0); + if (x->unk_0->unk_23 == 0) + { + x->unk_0->unk_8 = (void*)((U32)tpl + (U32)x->unk_0->unk_8); + x->unk_0->unk_23 = 1; + } + } + if (x->unk_4 != NULL) + { + x->unk_4 = (st_ISG_TPL_TEX::UnkOut*)((U32)tpl + (U32)x->unk_4); + if (x->unk_4->unk_2 == 0) + { + x->unk_4->unk_8 = tpl; + x->unk_4->unk_2 = 1; + } + } + } + return 1; +} + +static S32 iSG_bnr_unpack(st_ISG_TPL_TEXPALETTE* tpl) +{ + return iSG_tpl_unpack(tpl); +} + +static st_ISG_TPL_TEX* iSG_tpl_TEXGet(st_ISG_TPL_TEXPALETTE* tpl, U32 n) +{ + return &tpl->unk_8[n]; +} + +static void iSG_cb_unmount(s32 chan, s32 result); +static S32 iSG_mc_mount(S32 slot) +{ + s32 ret = 0; + // ?? for some reason this variable is in the stack frame + volatile s32 result = 0; + do + { + result = CARDMount(slot, cardwork[slot], iSG_cb_unmount); + isMounted = 1; + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + ret = 1; + } + else if (result == CARD_RESULT_BROKEN || result == CARD_RESULT_ENCODING) + { + ret = 1; + } + return ret; +} + +static void iSG_cb_unmount(s32 chan, s32 result) +{ + st_ISGSESSION* session = &g_isgdata_MAIN; + if (chan != session->slot) + { + return; + } + session->slot = -1; + if (session->chgfunc != NULL) + { + session->chgfunc(session->cltdata, ISG_CHG_TARGET); + } + memset(&session->mcdata[chan], 0, sizeof(st_ISG_MEMCARD_DATA)); +} + +static S32 iSG_mc_format(st_ISG_MEMCARD_DATA* mcdata, S32, S32* canRecover) +{ + if (mcdata->unk_12c != 0) + { + if (canRecover != NULL) + { + *canRecover = 0; + } + return 0; + } + + if (canRecover != NULL) + { + *canRecover = 1; + } + + s32 result; + do + { + result = CARDFormat(mcdata->chan); + } while (result == CARD_RESULT_BUSY); + + S32 ret; + if (result == CARD_RESULT_READY) + { + ret = 1; + } + else + { + ret = 0; + + switch (result) + { + case CARD_RESULT_IOERROR: + mcdata->unk_12c = 1; + if (canRecover != NULL) + { + *canRecover = 0; + } + break; + case CARD_RESULT_NOCARD: + if (canRecover != NULL) + { + *canRecover = -1; + } + ret = -1; + break; + case CARD_RESULT_FATAL_ERROR: + case CARD_RESULT_WRONGDEVICE: + case CARD_RESULT_NOFILE: + break; + } + } + return ret; +} + +static S32 iSG_mc_fopen(st_ISG_MEMCARD_DATA* mcdata, const char* fname, S32 fsize, + en_ISG_IOMODE mode, en_ASYNC_OPERR* operr) +{ + S32 ret = 0; + CARDFileInfo* finfo = &mcdata->finfo; + CARDStat* stat = &mcdata->fstat; + if (operr != NULL) + { + *operr = ISG_OPERR_NONE; + } + + if (mode == ISG_IOMODE_READ) + { + s32 result; + do + { + result = CARDOpen(mcdata->chan, (char*)fname, finfo); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + ret = 1; + } + } + else + { + S32 res = iSG_mc_fdel(mcdata, fname); + if (mcdata->unk_12c == 0 && res > 0) + { + s32 result; + do + { + result = CARDCreate(mcdata->chan, (char*)fname, fsize, finfo); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + ret = 1; + mcdata->unk_98 = 0; + } + else if (operr != NULL) + { + switch (result) + { + case CARD_RESULT_WRONGDEVICE: + case CARD_RESULT_NOCARD: + *operr = ISG_OPERR_NOCARD; + break; + case CARD_RESULT_IOERROR: + case CARD_RESULT_BROKEN: + mcdata->unk_12c = 1; + *operr = ISG_OPERR_DAMAGE; + break; + case CARD_RESULT_NOENT: + case CARD_RESULT_INSSPACE: + *operr = ISG_OPERR_NOROOM; + break; + default: + *operr = ISG_OPERR_OTHER; + break; + case CARD_RESULT_READY: + case CARD_RESULT_BUSY: + case CARD_RESULT_EXIST: + case CARD_RESULT_NOPERM: + break; + } + } + } + } + + if (ret != 0) + { + s32 result; + do + { + result = CARDGetStatus(mcdata->chan, finfo->fileNo, stat); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + ret = 1; + } + } + + if (ret != 0) + { + if (memcmp(stat->gameName, "GQPE", 4) != 0 || memcmp(stat->company, "78", 2) != 0) + { + iSG_mc_fclose(mcdata); + ret = 0; + } + } + + return ret; +} + +static S32 iSG_mc_fclose(st_ISG_MEMCARD_DATA* mcdata) +{ + iSG_mc_fclose(mcdata, NULL); +} + +static S32 iSG_mc_fclose(st_ISG_MEMCARD_DATA* mcdata, CARDStat* stat) +{ + S32 ret = 0; + s32 result; + do + { + result = CARDClose(&mcdata->finfo); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + ret = 1; + } + + if (stat != NULL) + { + memcpy(stat, &mcdata->fstat, sizeof(CARDStat)); + } + + memset(&mcdata->finfo, 0, sizeof(CARDFileInfo)); + memset(&mcdata->fstat, 0, sizeof(CARDStat)); + + return ret; +} + +static S32 iSG_mc_fdel(st_ISG_MEMCARD_DATA* mcdata, const char* fname) +{ + if (mcdata->chan < 0 || mcdata->chan > 1) + { + return 0; + } + + if (isMounted == 0) + { + return 0; + } + + s32 result; + do + { + result = CARDDelete(mcdata->chan, fname); + } while (result == CARD_RESULT_BUSY); + + S32 ret; + if (result == CARD_RESULT_NOFILE) + { + ret = 1; + } + else if (result == CARD_RESULT_READY) + { + ret = 1; + } + else + { + ret = 0; + switch (result) + { + case CARD_RESULT_IOERROR: + mcdata->unk_12c = 1; + break; + case CARD_RESULT_NOPERM: + case CARD_RESULT_FATAL_ERROR: + case CARD_RESULT_WRONGDEVICE: + break; + } + } + return ret; +} + +static S32 iSG_mcqa_fread(st_ISG_MEMCARD_DATA* mcdata, char* buf, S32 len, S32 offset); +static S32 iSG_mc_fread(st_ISG_MEMCARD_DATA* mcdata, char* buf, S32 len, S32 offset) +{ + return iSG_mcqa_fread(mcdata, buf, len, offset); +} + +static void iSG_cb_asyndone(s32, s32); +static S32 iSG_mcqa_fread(st_ISG_MEMCARD_DATA* mcdata, char* buf, S32 len, S32 offset) +{ + S32 x = 1000; + s32 result = CARDGetResultCode(mcdata->chan); + do + { + result = CARDGetResultCode(mcdata->chan); + } while (result == CARD_RESULT_BUSY); + + if (result != CARD_RESULT_READY) + { + return 0; + } + + CARDGetXferredBytes(mcdata->chan); + do + { + result = CARDReadAsync(&mcdata->finfo, buf, len, offset, iSG_cb_asyndone); + } while (result == CARD_RESULT_BUSY); + + if (result != CARD_RESULT_READY) + { + return 0; + } + + result = CARD_RESULT_BUSY; + do + { + if (x++ > 500) + { + xSndUpdate(); + CARDGetXferredBytes(mcdata->chan); + result = CARDGetResultCode(mcdata->chan); + x = 0; + } + iTRCDisk::CheckDVDAndResetState(); + } while (result == CARD_RESULT_BUSY); + return result != 0 ? 0 : 1; +} + +static S32 iSG_mcqa_fwrite(st_ISG_MEMCARD_DATA* mcdata, char* buf, S32 len); +static S32 iSG_mc_fwrite(st_ISG_MEMCARD_DATA* mcdata, char* buf, S32 len) +{ + iSG_mcqa_fwrite(mcdata, buf, len); +} + +static S32 iSG_mcqa_fwrite(st_ISG_MEMCARD_DATA* mcdata, char* buf, S32 len) +{ + S32 ret = 0; + S32 x = 1000; + CARDStat* fstat = &mcdata->fstat; + s32 result; + do + { + result = CARDGetResultCode(mcdata->chan); + } while (result == CARD_RESULT_BUSY); + + if (result != CARD_RESULT_READY) + { + return 0; + } + + CARDGetXferredBytes(mcdata->chan); + s32 asynresult; + do + { + asynresult = CARDWriteAsync(&mcdata->finfo, buf, len, mcdata->unk_98, iSG_cb_asyndone); + } while (asynresult == CARD_RESULT_BUSY); + + if (asynresult != CARD_RESULT_READY) + { + return 0; + } + + result = CARD_RESULT_BUSY; + do + { + if (x++ > 500) + { + result = CARDGetResultCode(mcdata->chan); + xSndUpdate(); + CARDGetXferredBytes(mcdata->chan); + x = 0; + } + iTRCDisk::CheckDVDAndResetState(); + } while (result == CARD_RESULT_BUSY); + + if (asynresult == CARD_RESULT_READY) + { + mcdata->unk_98 += len; + + do + { + result = CARDGetStatus(mcdata->chan, mcdata->finfo.fileNo, fstat); + } while (result == CARD_RESULT_BUSY); + + if (result == CARD_RESULT_READY) + { + ret = 1; + } + } + return ret; +} + +S32 iSGCheckForWrongDevice() +{ + char* workarea = (char*)RwMalloc(0x10000 - 0x6000); + + S32 ret = -1; + for (S32 i = 0; i < ISG_NUM_SLOTS; ++i) + { + s32 result = CARDMount(i, workarea, NULL); + + switch (result) + { + case CARD_RESULT_READY: + case CARD_RESULT_BROKEN: + case CARD_RESULT_ENCODING: + CARDUnmount(i); + break; + case CARD_RESULT_WRONGDEVICE: + ret = i; + i = ISG_NUM_SLOTS; + break; + } + } + + RwFree(workarea); + + return ret; +} + +S32 iSGCheckForCorruptFiles(st_ISGSESSION* isgdata, char files[][64]) +{ + if (isgdata->slot < 0) + { + return 0; + } + + S32 i; + char* name; + st_ISG_MEMCARD_DATA* mcdata = &isgdata->mcdata[isgdata->slot]; + S32 ret = 0; + memset(files, NULL, 0xc0); + + for (i = 0; i < ISG_NUM_FILES; ++i) + { + name = iSGMakeName(ISG_NGTYP_GAMEFILE, NULL, i); + if (iSG_fileKosher(mcdata, name, 0, NULL) == 0) + { + strcpy(files[ret], name); + ret++; + } + } + return ret; +} + +U8 iSGCheckMemoryCard(st_ISGSESSION* isgdata, S32 index) +{ + s32 memSize; + s32 sectorSize; + + switch (CARDProbeEx(index, &memSize, §orSize)) + { + case CARD_RESULT_READY: + return 1; + } + return 0; +} + static S32 iSG_mc_unmount(S32 slot) { S32 rc = 0; @@ -1423,10 +1989,47 @@ static S32 iSG_mc_unmount(S32 slot) return rc; } -static void iSG_cb_asyndone(long, long) +static void iSG_cb_asyndone(s32, s32) { } void iSGAutoSave_Startup() { } + +st_ISGSESSION* iSGAutoSave_Connect(S32 idx_target, void* cltdata, void (*chg)(void*, en_CHGCODE)) +{ + st_ISGSESSION* isgdata = iSGSessionBegin(cltdata, chg, 1); + if (isgdata == NULL) + { + return isgdata; + } + + if (iSGTgtSetActive(isgdata, idx_target) == 0) + { + iSGSessionEnd(isgdata); + isgdata = NULL; + } + return isgdata; +} + +void iSGAutoSave_Disconnect(st_ISGSESSION* isg) +{ + iSGSessionEnd(isg); +} + +S32 iSGAutoSave_Monitor(st_ISGSESSION* isg, S32 idx_target) +{ + if (isg == NULL) + { + return 0; + } + + U32 ret = iSGTgtState(isg, idx_target, NULL); + if (ret == 0 || (ret & 1) == 0) + { + globals.autoSaveFeature = 0; + return 0; + } + return 1; +} diff --git a/src/SB/Core/gc/isavegame.h b/src/SB/Core/gc/isavegame.h index 4e7644ec2..e18c5d46f 100644 --- a/src/SB/Core/gc/isavegame.h +++ b/src/SB/Core/gc/isavegame.h @@ -110,11 +110,12 @@ class st_ISGSESSION { struct st_ISG_MEMCARD_DATA { S32 unk_0; - S32 unk_4; + S32 chan; S32 sectorSize; - CARDFileInfo unk_c; - CARDStat unk_20; - S32 unk_pad5[4]; + CARDFileInfo finfo; + CARDStat fstat; + S32 unk_pad5[3]; + S32 unk_98; CARDFileInfo unk_9c; CARDStat unk_b0; S32 unk_pad6[4];