From 6a99508ee59e1b54546f1dfc03034975efe14f55 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Tue, 27 Dec 2016 22:51:28 -1000 Subject: [PATCH 1/2] kabufuda integration --- Editor/platforms/mac/mainicon.icns | Bin 973983 -> 1242927 bytes Runtime/CMemoryCardSys.cpp | 193 +++++++++++++++++++++-------- Runtime/CMemoryCardSys.hpp | 166 ++++++++----------------- Runtime/MP1/CMemoryCardDriver.cpp | 65 +++++----- Runtime/MP1/CMemoryCardDriver.hpp | 58 ++++----- Runtime/MP1/CSaveUI.cpp | 4 +- kabufuda | 2 +- 7 files changed, 247 insertions(+), 241 deletions(-) diff --git a/Editor/platforms/mac/mainicon.icns b/Editor/platforms/mac/mainicon.icns index 3872e86130ef7dd7dd93b016b7538c8522297dd6..7b74f7de2915a0fbe074e90a221728cc0760aea7 100644 GIT binary patch delta 33408 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 E0Af7Nk^lez delta 33105 zcmZ_0XLM9owl2C+CQ5*iD(79bD<|cMG9W|}K?IS6KqLtyp^Wz4RV7tY7DD7~3>eck z#wKTMoZ4>3cIbAW)c3vn#<=&~d&e7hjQ8ujZ|xG;?(^QTYuF&wx93`GuDRy?zPa`v z{(I%wySWLw>l$0AIe$6p|KCrNZvXEmb3;i{j%!e5T_w1D~0xzf`z^YgPDMtn)7l5x@~mCfOyr0Gt#+rn5KE?1h_WHe}1a+O@lN@a4H z#+uGiH72_&EzKlXC~1pDp;RekDwR?xNtMWDa<$n+Q6`Jo<}jID7Og_Au^N>UsZ=Zx zixf(!RA$7_4VVVA(Uy_svKg&TlU62?i1DvZ%}Hm{28uG9)LK1bb$OgIcB57S!=fc} z)~w?^P%~o_ zMIsHOSBnH56rA*RG(gu08ENC*Y%_2TQBg7Z+u$ zt<*@Cu~Z?>E)>C&Dkk6H zDR#}dp_RtcGM6QLkz?JaJ$q_atMg52Q+~c|$Dz*bf%NzES$P}D%T!Jw~RO&d+7JhMh6USPXcG(YN|+_ys}&*747g*)b##?a+Ru}DOb;M#%M;Tgr}xRQmy;5QzfGPhbgM7 zMXS)5Hn)_}29{$MXqE6(i75BLI+aAMIM_~6IUQ~pr%zejzTS+;pvA@&DONWxluD!v ztZg|QCFN@o88nLA{q+u7kME20Tlb}j0HWB`3vb*r(papO$fSnamW7ybN$#Od+Ej6h zqF~=p1AZ*wL)>2bT!~Cw#U3hBN^{$m%EaQi_C5Ury$j&2baSBVV9p$gTw1o%W^X8g z@rgMthX)QC;H@*Z_4IeR=SXCxy$yT!Sw*7RX`O-I9W(q?a()|suqZJ_wf*4UI_2Ei z#Ru8ete7A*H>-zhFK2Ys2OBr5b>)Zn?i_gQ3SYo;X#eE@^FQa!6LmFsy6U>SJ6e~; z4pTE1w*VsxyYafQx?7lkVKNd*zD!raF~Iyr?df?)nBU`uXiVb6&@ejq6MH z?@(%_?gPqH*R2oxsg(bCyiaS(?^?NfMc$t63bkC@sF#WMJc09G`+&{WnF?ES%ZgnM z+vF;RsKF%?XWlyt5B=sWLo@D6%qWvwCZ7 zsyubkid3;EW!qQ(L_GATCp($7>vAkb8=Qx_M#nnZ=w<0z_p%kT?Js_Shu(R%T4iXi zFRpIb($u$xUA1CWf5Vo2tMazgi<6f4r_WQ=vMaeFoKBn1x0=;7 zjaVs7Q5`(9Mk1EZ%Y0)A9Q5X4y+W;&Ek5RVt95FHEY;#Y20xN4P#wMw4-9`aS*;UE z#a7RmDy3Q>T6~UWQp5{Xt0q1i#E%tkKYVXAH%TJV)Sq9$%EXoD>lLY@q`c94Pp(Md zpzdS$-#W2$Hul@5(X8wv8|I5sXD>T@u zt3L@2TKnd$bL(f%*Z4+<0=hY~HlBO$(puu6D{sE{<~FDP;KZ0mZ{2qJ=G!abpiOu0 zzkl(_!fm(n%3#ejD=ClC`$J&6{oUT^j52d zGb>CcoW?kAoi2yd>2Nw&r^9Zsm`!Gj*=%AgIbTyLIJ;?+-fDNa-Dzp*85!wr{JO)+ z+2&hqILC0(k?-5BMpwFymV8c4SD6?SgD<3IaGBFG(z�ZWrf_aoEjPD`%NzHuI)A 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 diff --git a/Runtime/CMemoryCardSys.cpp b/Runtime/CMemoryCardSys.cpp index b518e2a38..ee1590c65 100644 --- a/Runtime/CMemoryCardSys.cpp +++ b/Runtime/CMemoryCardSys.cpp @@ -9,6 +9,11 @@ namespace urde { +using ECardResult = kabufuda::ECardResult; + +kabufuda::SystemString g_CardImagePaths[2] = {}; +kabufuda::Card g_CardStates[2] = {}; + CSaveWorldIntermediate::CSaveWorldIntermediate(ResId mlvl, ResId savw) : x0_mlvlId(mlvl), x8_savwId(savw) { @@ -140,10 +145,11 @@ void CMemoryCardSys::CCardFileInfo::LockBannerToken(ResId bannerTxtr, CSimplePoo x40_bannerTok.emplace(sp.GetObj({FOURCC('TXTR'), bannerTxtr}, m_texParam)); } -CMemoryCardSys::CCardFileInfo::Icon::Icon(ResId id, u32 speed, CSimplePool& sp, const CVParamTransfer& cv) +CMemoryCardSys::CCardFileInfo::Icon::Icon(ResId id, kabufuda::EAnimationSpeed speed, + CSimplePool& sp, const CVParamTransfer& cv) : x0_id(id), x4_speed(speed), x8_tex(sp.GetObj({FOURCC('TXTR'), id}, cv)) {} -void CMemoryCardSys::CCardFileInfo::LockIconToken(ResId iconTxtr, u32 speed, CSimplePool& sp) +void CMemoryCardSys::CCardFileInfo::LockIconToken(ResId iconTxtr, kabufuda::EAnimationSpeed speed, CSimplePool& sp) { x50_iconToks.emplace_back(iconTxtr, speed, sp, m_texParam); } @@ -239,7 +245,7 @@ void CMemoryCardSys::CCardFileInfo::WriteIconData(CMemoryOutStream& out) const out.writeBytes(palette.get(), 512); } -CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::PumpCardTransfer() +ECardResult CMemoryCardSys::CCardFileInfo::PumpCardTransfer() { if (x0_status == EStatus::Standby) return ECardResult::READY; @@ -251,7 +257,7 @@ CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::PumpCardTransfer() if (result != ECardResult::READY) return result; x0_status = EStatus::Done; - CARDStat stat = {}; + kabufuda::CardStat stat = {}; result = GetStatus(stat); if (result != ECardResult::READY) return result; @@ -269,7 +275,7 @@ CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::PumpCardTransfer() } } -CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::GetStatus(CARDStat& stat) const +ECardResult CMemoryCardSys::CCardFileInfo::GetStatus(kabufuda::CardStat& stat) const { ECardResult result = CMemoryCardSys::GetStatus(GetCardPort(), GetFileNo(), stat); if (result != ECardResult::READY) @@ -278,112 +284,193 @@ CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::GetStatus(CARDStat& s stat.SetCommentAddr(4); stat.SetIconAddr(68); - u32 bannerFmt; + kabufuda::EImageFormat bannerFmt; if (x3c_bannerTex != -1) { if ((*x40_bannerTok)->GetMemoryCardTexelFormat() == ETexelFormat::RGB5A3) - bannerFmt = 2; + bannerFmt = kabufuda::EImageFormat::RGB5A3; else - bannerFmt = 1; + bannerFmt = kabufuda::EImageFormat::C8; } else - bannerFmt = 0; + bannerFmt = kabufuda::EImageFormat::None; stat.SetBannerFormat(bannerFmt); int idx = 0; for (const Icon& icon : x50_iconToks) { - stat.SetIconFormat(icon.x8_tex->GetMemoryCardTexelFormat() == ETexelFormat::RGB5A3 ? 2 : 1, idx); + stat.SetIconFormat(icon.x8_tex->GetMemoryCardTexelFormat() == ETexelFormat::RGB5A3 ? + kabufuda::EImageFormat::RGB5A3 : kabufuda::EImageFormat::C8, idx); stat.SetIconSpeed(icon.x4_speed, idx); ++idx; } if (idx < 8) { - stat.SetIconFormat(0, idx); - stat.SetIconSpeed(0, idx); + stat.SetIconFormat(kabufuda::EImageFormat::None, idx); + stat.SetIconSpeed(kabufuda::EAnimationSpeed::End, idx); } return ECardResult::READY; } -CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::CreateFile() +ECardResult CMemoryCardSys::CCardFileInfo::CreateFile() { - return ECardResult::READY; + return CMemoryCardSys::CreateFile(m_handle.slot, x18_fileName.c_str(), + CalculateTotalDataSize(), m_handle); } -CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::Write() +ECardResult CMemoryCardSys::CCardFileInfo::WriteFile() { BuildCardBuffer(); - //DCStoreRange(info.x104_cardBuffer.data(), info.x104_cardBuffer.size()); - //CARDWriteAsync(&info.x4_info, info.x104_cardBuffer.data(), info.x104_cardBuffer.size(), 0, 0); + //DCStoreRange(x104_cardBuffer.data(), x104_cardBuffer.size()); + return CMemoryCardSys::WriteFile(m_handle, x104_cardBuffer.data(), x104_cardBuffer.size(), 0); +} + +ECardResult CMemoryCardSys::CCardFileInfo::CloseFile() +{ + return CMemoryCardSys::CloseFile(m_handle); +} + +kabufuda::ProbeResults CMemoryCardSys::CardProbe(kabufuda::ECardSlot port) +{ + return kabufuda::Card::probeCardFile(g_CardImagePaths[int(port)]); +} + +ECardResult CMemoryCardSys::MountCard(kabufuda::ECardSlot port) +{ + kabufuda::Card& card = g_CardStates[int(port)]; + card = kabufuda::Card(g_CardImagePaths[int(port)], "GM8E", "01"); + ECardResult result = card.getError(); + if (result == ECardResult::READY) + return ECardResult::READY; + card = kabufuda::Card(); + return result; +} + +ECardResult CMemoryCardSys::CheckCard(kabufuda::ECardSlot port) +{ + kabufuda::Card& card = g_CardStates[int(port)]; + return card.getError(); +} + +ECardResult CMemoryCardSys::CreateFile(kabufuda::ECardSlot port, const char* name, u32 size, CardFileHandle& info) +{ + kabufuda::Card& card = g_CardStates[int(port)]; + if (CardResult err = card.getError()) + return err; + info.slot = port; + return card.createFile(name, size, info.handle); +} + +ECardResult CMemoryCardSys::OpenFile(kabufuda::ECardSlot port, const char* name, CardFileHandle& info) +{ + kabufuda::Card& card = g_CardStates[int(port)]; + if (CardResult err = card.getError()) + return err; + info.slot = port; + info.handle = card.openFile(name); + return info.handle ? ECardResult::READY : ECardResult::NOFILE; +} + +ECardResult CMemoryCardSys::FastOpenFile(kabufuda::ECardSlot port, int fileNo, CardFileHandle& info) +{ + kabufuda::Card& card = g_CardStates[int(port)]; + if (CardResult err = card.getError()) + return err; + info.slot = port; + info.handle = card.openFile(fileNo); + return info.handle ? ECardResult::READY : ECardResult::NOFILE; +} + +ECardResult CMemoryCardSys::CloseFile(CardFileHandle& info) +{ + info.handle.reset(); return ECardResult::READY; } -CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::Close() +ECardResult CMemoryCardSys::ReadFile(const CardFileHandle& info, void* buf, s32 length, s32 offset) { - EMemoryCardPort port = GetCardPort(); - //CARDClose(port); - x4_info.chan = port; + kabufuda::Card& card = g_CardStates[int(info.slot)]; + if (CardResult err = card.getError()) + return err; + card.seek(info, offset, kabufuda::SeekOrigin::Begin); + card.read(info, buf, length); return ECardResult::READY; } -CMemoryCardSys::CardProbeResults CMemoryCardSys::CardProbe(EMemoryCardPort port) +ECardResult CMemoryCardSys::WriteFile(const CardFileHandle& info, const void* buf, s32 length, s32 offset) { - return {}; + kabufuda::Card& card = g_CardStates[int(info.slot)]; + if (CardResult err = card.getError()) + return err; + card.seek(info, offset, kabufuda::SeekOrigin::Begin); + card.write(info, buf, length); + return ECardResult::READY; } -CMemoryCardSys::ECardResult CMemoryCardSys::MountCard(EMemoryCardPort port) +ECardResult CMemoryCardSys::GetNumFreeBytes(kabufuda::ECardSlot port, s32& freeBytes, s32& freeFiles) +{ + kabufuda::Card& card = g_CardStates[int(port)]; + if (CardResult err = card.getError()) + return err; + card.getFreeBlocks(freeBytes, freeFiles); + return ECardResult::READY; +} + +ECardResult CMemoryCardSys::GetSerialNo(kabufuda::ECardSlot port, u64& serialOut) +{ + kabufuda::Card& card = g_CardStates[int(port)]; + if (CardResult err = card.getError()) + return err; + card.getSerial(serialOut); + return ECardResult::READY; +} + +ECardResult CMemoryCardSys::GetResultCode(kabufuda::ECardSlot port) { return ECardResult::READY; } -CMemoryCardSys::ECardResult CMemoryCardSys::CheckCard(EMemoryCardPort port) +ECardResult CMemoryCardSys::GetStatus(kabufuda::ECardSlot port, int fileNo, CardStat& statOut) { return ECardResult::READY; } -CMemoryCardSys::ECardResult CMemoryCardSys::GetNumFreeBytes(EMemoryCardPort port, s32& freeBytes, s32& freeFiles) +ECardResult CMemoryCardSys::SetStatus(kabufuda::ECardSlot port, int fileNo, const CardStat& stat) { return ECardResult::READY; } -CMemoryCardSys::ECardResult CMemoryCardSys::GetSerialNo(EMemoryCardPort port, u64& serialOut) +ECardResult CMemoryCardSys::DeleteFile(kabufuda::ECardSlot port, const char* name) { - return ECardResult::READY; + kabufuda::Card& card = g_CardStates[int(port)]; + if (CardResult err = card.getError()) + return err; + return card.deleteFile(name); } -CMemoryCardSys::ECardResult CMemoryCardSys::GetResultCode(EMemoryCardPort port) +ECardResult CMemoryCardSys::FastDeleteFile(kabufuda::ECardSlot port, int fileNo) { - return ECardResult::READY; + kabufuda::Card& card = g_CardStates[int(port)]; + if (CardResult err = card.getError()) + return err; + return card.deleteFile(fileNo); } -CMemoryCardSys::ECardResult CMemoryCardSys::GetStatus(EMemoryCardPort port, int fileNo, CARDStat& statOut) +ECardResult CMemoryCardSys::Rename(kabufuda::ECardSlot port, const char* oldName, const char* newName) { - return ECardResult::READY; + kabufuda::Card& card = g_CardStates[int(port)]; + if (CardResult err = card.getError()) + return err; + return card.renameFile(oldName, newName); } -CMemoryCardSys::ECardResult CMemoryCardSys::SetStatus(EMemoryCardPort port, int fileNo, const CARDStat& stat) -{ - return ECardResult::READY; -} - -CMemoryCardSys::ECardResult CMemoryCardSys::DeleteFile(EMemoryCardPort port, const char* name) -{ - return ECardResult::READY; -} - -CMemoryCardSys::ECardResult CMemoryCardSys::FastDeleteFile(EMemoryCardPort port, int fileNo) -{ - return ECardResult::READY; -} - -CMemoryCardSys::ECardResult CMemoryCardSys::Rename(EMemoryCardPort port, const char* oldName, const char* newName) -{ - return ECardResult::READY; -} - -CMemoryCardSys::ECardResult CMemoryCardSys::FormatCard(EMemoryCardPort port) +ECardResult CMemoryCardSys::FormatCard(kabufuda::ECardSlot port) { + kabufuda::Card& card = g_CardStates[int(port)]; + if (CardResult err = card.getError()) + return err; + card.format(port); return ECardResult::READY; } diff --git a/Runtime/CMemoryCardSys.hpp b/Runtime/CMemoryCardSys.hpp index 679ccc1d7..6f9d8876c 100644 --- a/Runtime/CMemoryCardSys.hpp +++ b/Runtime/CMemoryCardSys.hpp @@ -6,15 +6,9 @@ #include "CGameHintInfo.hpp" #include "CSaveWorld.hpp" #include "GuiSys/CStringTable.hpp" +#include "kabufuda/Card.hpp" #include -#undef NOFILE - -// longest file name string excluding terminating zero -#define CARD_FILENAME_MAX 32 - -#define CARD_ICON_MAX 8 - namespace urde { class CDummyWorld; @@ -64,105 +58,40 @@ class CMemoryCardSys std::experimental::optional> x1c_worldInter; /* used to be auto_ptr of vector */ std::vector> x20_scanStates; public: + using ECardResult = kabufuda::ECardResult; + struct CardResult + { + ECardResult result; + CardResult(ECardResult res) : result(res) {} + operator ECardResult() const { return result; } + operator bool() const { return result != ECardResult::READY; } + }; + + struct CardFileHandle + { + kabufuda::ECardSlot slot; + std::unique_ptr handle; + CardFileHandle(kabufuda::ECardSlot slot) : slot(slot) {} + kabufuda::IFileHandle* operator->() const { return handle.get(); } + operator std::unique_ptr&() { return handle; } + operator const std::unique_ptr&() const { return handle; } + }; + + using CardStat = kabufuda::CardStat; const std::vector& GetHints() const { return x0_hints->GetHints(); } const std::vector>& GetMemoryWorlds() const { return xc_memoryWorlds; } const std::vector>& GetScanStates() const { return x20_scanStates; } CMemoryCardSys(); bool InitializePump(); - enum class EMemoryCardPort - { - SlotA, - SlotB - }; - - enum class ECardResult - { - CRC_MISMATCH = -1003, - FATAL_ERROR = -128, - ENCODING = -13, - BROKEN = -6, - IOERROR = -5, - NOFILE = -4, - NOCARD = -3, - WRONGDEVICE = -2, - BUSY = -1, - READY = 0 - }; - - struct CardProbeResults - { - ECardResult x0_error; - u32 x4_cardSize; // in megabits - u32 x8_sectorSize; // in bytes - }; - - struct CARDStat - { - // read-only (Set by CARDGetStatus) - char x0_fileName[CARD_FILENAME_MAX]; - u32 x20_length; - u32 x24_time; // seconds since 01/01/2000 midnight - u8 x28_gameName[4]; - u8 x2c_company[2]; - - // read/write (Set by CARDGetStatus/CARDSetStatus) - u8 x2e_bannerFormat; - u8 x2f___padding; - u32 x30_iconAddr; // offset to the banner, bannerTlut, icon, iconTlut data set. - u16 x34_iconFormat; - u16 x36_iconSpeed; - u32 x38_commentAddr; // offset to the pair of 32 byte character strings. - - // read-only (Set by CARDGetStatus) - u32 x3c_offsetBanner; - u32 x40_offsetBannerTlut; - u32 x44_offsetIcon[CARD_ICON_MAX]; - u32 x64_offsetIconTlut; - u32 x68_offsetData; - - u32 GetFileLength() const { return x20_length; } - u32 GetTime() const { return x24_time; } - u32 GetBannerFormat() const { return x2e_bannerFormat & 0x3; } - void SetBannerFormat(u32 fmt) { x2e_bannerFormat = (x2e_bannerFormat & ~0x3) | fmt; } - u32 GetIconFormat(int idx) const { return (x34_iconFormat >> (idx * 2)) & 0x3; } - void SetIconFormat(u32 fmt, int idx) - { - x34_iconFormat &= ~(0x3 << (idx * 2)); - x34_iconFormat |= fmt << (idx * 2); - } - void SetIconSpeed(u32 sp, int idx) - { - x36_iconSpeed &= ~(0x3 << (idx * 2)); - x36_iconSpeed |= sp << (idx * 2); - } - u32 GetIconAddr() const { return x30_iconAddr; } - void SetIconAddr(u32 addr) { x30_iconAddr = addr; } - u32 GetCommentAddr() const { return x38_commentAddr; } - void SetCommentAddr(u32 addr) { x38_commentAddr = addr; } - }; - - struct CARDFileInfo - { - EMemoryCardPort chan; - s32 fileNo = -1; - - s32 offset; - s32 length; - u16 iBlock; - u16 __padding; - - CARDFileInfo(EMemoryCardPort port) : chan(port) {} - }; - struct CCardFileInfo { struct Icon { ResId x0_id; - u32 x4_speed; + kabufuda::EAnimationSpeed x4_speed; TLockedToken x8_tex; - Icon(ResId id, u32 speed, CSimplePool& sp, const CVParamTransfer& cv); + Icon(ResId id, kabufuda::EAnimationSpeed speed, CSimplePool& sp, const CVParamTransfer& cv); }; enum class EStatus @@ -173,7 +102,8 @@ public: }; EStatus x0_status = EStatus::Standby; - CARDFileInfo x4_info; + //CARDFileInfo x4_info; + CardFileHandle m_handle; std::string x18_fileName; std::string x28_comment; ResId x3c_bannerTex = -1; @@ -184,14 +114,14 @@ public: CVParamTransfer m_texParam = {new TObjOwnerParam(SBIG('OTEX'))}; - CCardFileInfo(EMemoryCardPort port, const std::string& name) - : x4_info(port), x18_fileName(name) {} + CCardFileInfo(kabufuda::ECardSlot port, const std::string& name) + : m_handle(port), x18_fileName(name) {} void LockBannerToken(ResId bannerTxtr, CSimplePool& sp); - void LockIconToken(ResId iconTxtr, u32 speed, CSimplePool& sp); + void LockIconToken(ResId iconTxtr, kabufuda::EAnimationSpeed speed, CSimplePool& sp); - EMemoryCardPort GetCardPort() const { return x4_info.chan; } - int GetFileNo() const { return x4_info.fileNo; } + kabufuda::ECardSlot GetCardPort() const { return m_handle.slot; } + int GetFileNo() const { return m_handle->getFileNo(); } u32 CalculateBannerDataSize() const; u32 CalculateTotalDataSize() const; void BuildCardBuffer(); @@ -199,10 +129,10 @@ public: void WriteIconData(CMemoryOutStream& out) const; void SetComment(const std::string& c) { x28_comment = c; } ECardResult PumpCardTransfer(); - ECardResult GetStatus(CARDStat& stat) const; + ECardResult GetStatus(CardStat& stat) const; ECardResult CreateFile(); - ECardResult Write(); - ECardResult Close(); + ECardResult WriteFile(); + ECardResult CloseFile(); CMemoryOutStream BeginMemoryOut(u32 sz) { @@ -211,18 +141,24 @@ public: } }; - static CardProbeResults CardProbe(EMemoryCardPort port); - static ECardResult MountCard(EMemoryCardPort port); - static ECardResult CheckCard(EMemoryCardPort port); - static ECardResult GetNumFreeBytes(EMemoryCardPort port, s32& freeBytes, s32& freeFiles); - static ECardResult GetSerialNo(EMemoryCardPort port, u64& serialOut); - static ECardResult GetResultCode(EMemoryCardPort port); - static ECardResult GetStatus(EMemoryCardPort port, int fileNo, CARDStat& statOut); - static ECardResult SetStatus(EMemoryCardPort port, int fileNo, const CARDStat& stat); - static ECardResult DeleteFile(EMemoryCardPort port, const char* name); - static ECardResult FastDeleteFile(EMemoryCardPort port, int fileNo); - static ECardResult Rename(EMemoryCardPort port, const char* oldName, const char* newName); - static ECardResult FormatCard(EMemoryCardPort port); + static kabufuda::ProbeResults CardProbe(kabufuda::ECardSlot port); + static ECardResult MountCard(kabufuda::ECardSlot port); + static ECardResult CheckCard(kabufuda::ECardSlot port); + static ECardResult CreateFile(kabufuda::ECardSlot port, const char* name, u32 size, CardFileHandle& info); + static ECardResult OpenFile(kabufuda::ECardSlot port, const char* name, CardFileHandle& info); + static ECardResult FastOpenFile(kabufuda::ECardSlot port, int fileNo, CardFileHandle& info); + static ECardResult CloseFile(CardFileHandle& info); + static ECardResult ReadFile(const CardFileHandle& info, void* buf, s32 length, s32 offset); + static ECardResult WriteFile(const CardFileHandle& info, const void* buf, s32 length, s32 offset); + static ECardResult GetNumFreeBytes(kabufuda::ECardSlot port, s32& freeBytes, s32& freeFiles); + static ECardResult GetSerialNo(kabufuda::ECardSlot port, u64& serialOut); + static ECardResult GetResultCode(kabufuda::ECardSlot port); + static ECardResult GetStatus(kabufuda::ECardSlot port, int fileNo, CardStat& statOut); + static ECardResult SetStatus(kabufuda::ECardSlot port, int fileNo, const CardStat& stat); + static ECardResult DeleteFile(kabufuda::ECardSlot port, const char* name); + static ECardResult FastDeleteFile(kabufuda::ECardSlot port, int fileNo); + static ECardResult Rename(kabufuda::ECardSlot port, const char* oldName, const char* newName); + static ECardResult FormatCard(kabufuda::ECardSlot port); }; } diff --git a/Runtime/MP1/CMemoryCardDriver.cpp b/Runtime/MP1/CMemoryCardDriver.cpp index 1b27f805e..a16a3851a 100644 --- a/Runtime/MP1/CMemoryCardDriver.cpp +++ b/Runtime/MP1/CMemoryCardDriver.cpp @@ -13,27 +13,22 @@ static const char* SaveFileNames[] = "MetroidPrime B" }; -using ECardResult = CMemoryCardSys::ECardResult; -using EMemoryCardPort = CMemoryCardSys::EMemoryCardPort; +using ECardResult = kabufuda::ECardResult; +using ECardSlot = kabufuda::ECardSlot; ECardResult CMemoryCardDriver::SFileInfo::Open() { - //CARDOpen(GetFileCardPort(), x14_name.data(), &x0_fileInfo); - return ECardResult::READY; + return CMemoryCardSys::OpenFile(GetFileCardPort(), x14_name.c_str(), x0_fileInfo); } ECardResult CMemoryCardDriver::SFileInfo::Close() { - auto backup = GetFileCardPort(); - ECardResult result = ECardResult::READY; - //result = CARDClose(backup); - x0_fileInfo.x0_cardPort = backup; - return result; + return CMemoryCardSys::CloseFile(x0_fileInfo); } -CMemoryCardSys::ECardResult CMemoryCardDriver::SFileInfo::StartRead() +ECardResult CMemoryCardDriver::SFileInfo::StartRead() { - CMemoryCardSys::CARDStat stat = {}; + CMemoryCardSys::CardStat stat = {}; ECardResult result = CMemoryCardSys::GetStatus(GetFileCardPort(), GetFileNo(), stat); if (result != ECardResult::READY) return result; @@ -41,8 +36,7 @@ CMemoryCardSys::ECardResult CMemoryCardDriver::SFileInfo::StartRead() u32 length = stat.GetFileLength(); x34_saveData.clear(); x24_saveFileData.resize(length); - //return CARDReadAsync(&x0_fileInfo, x24_saveFileData.data(), length, 0, 0); - return ECardResult::READY; + return CMemoryCardSys::ReadFile(x0_fileInfo, x24_saveFileData.data(), length, 0); } ECardResult CMemoryCardDriver::SFileInfo::TryFileRead() @@ -83,7 +77,7 @@ ECardResult CMemoryCardDriver::SFileInfo::FileRead() ECardResult CMemoryCardDriver::SFileInfo::GetSaveDataOffset(u32& offOut) { - CMemoryCardSys::CARDStat stat = {}; + CMemoryCardSys::CardStat stat = {}; ECardResult result = CMemoryCardSys::GetStatus(GetFileCardPort(), GetFileNo(), stat); if (result != ECardResult::READY) { @@ -95,10 +89,10 @@ ECardResult CMemoryCardDriver::SFileInfo::GetSaveDataOffset(u32& offOut) offOut += 64; switch (stat.GetBannerFormat()) { - case 1: + case kabufuda::EImageFormat::C8: offOut += 3584; break; - case 2: + case kabufuda::EImageFormat::RGB5A3: offOut += 6144; break; default: break; @@ -106,9 +100,11 @@ ECardResult CMemoryCardDriver::SFileInfo::GetSaveDataOffset(u32& offOut) int idx = 0; bool paletteIcon = false; - while (u32 fmt = stat.GetIconFormat(idx)) + for (kabufuda::EImageFormat fmt = stat.GetIconFormat(idx); + fmt != kabufuda::EImageFormat::None; + fmt = stat.GetIconFormat(idx)) { - if (fmt == 1) + if (fmt == kabufuda::EImageFormat::C8) { paletteIcon = true; offOut += 1024; @@ -142,14 +138,10 @@ void CMemoryCardDriver::SGameFileSlot::InitializeFromGameState() x944_fileInfo = CGameState::LoadGameFileState(x0_saveBuffer); } -CMemoryCardDriver::SFileInfo::SFileInfo(EMemoryCardPort port, - const std::string& name) -: x14_name(name) -{ - x0_fileInfo.x0_cardPort = port; -} +CMemoryCardDriver::SFileInfo::SFileInfo(kabufuda::ECardSlot port, const std::string& name) +: x0_fileInfo(port), x14_name(name) {} -CMemoryCardDriver::CMemoryCardDriver(EMemoryCardPort cardPort, ResId saveBanner, +CMemoryCardDriver::CMemoryCardDriver(kabufuda::ECardSlot cardPort, ResId saveBanner, ResId saveIcon0, ResId saveIcon1, bool importPersistent) : x0_cardPort(cardPort), x4_saveBanner(saveBanner), x8_saveIcon0(saveIcon0), xc_saveIcon1(saveIcon1), x19d_doImportPersistent(importPersistent) @@ -189,10 +181,9 @@ std::unique_ptr CMemoryCardDriver::LoadSaveFil void CMemoryCardDriver::ReadFinished() { - CMemoryCardSys::CARDStat stat = {}; + CMemoryCardSys::CardStat stat = {}; SFileInfo& fileInfo = x100_mcFileInfos[x194_fileIdx].second; - if (CMemoryCardSys::GetStatus(x0_cardPort, fileInfo.GetFileNo(), stat) != - ECardResult::READY) + if (CMemoryCardSys::GetStatus(x0_cardPort, fileInfo.GetFileNo(), stat) != ECardResult::READY) { NoCardFound(); return; @@ -247,9 +238,9 @@ void CMemoryCardDriver::IndexFiles() } else if (result == ECardResult::READY) { - CMemoryCardSys::CARDStat stat = {}; + CMemoryCardSys::CardStat stat = {}; if (CMemoryCardSys::GetStatus(x0_cardPort, info.second.GetFileNo(), stat) == - ECardResult::READY) + ECardResult::READY) { u32 comment = stat.GetCommentAddr(); if (comment == -1) @@ -280,7 +271,7 @@ void CMemoryCardDriver::IndexFiles() { if (x100_mcFileInfos[1].first == EFileState::File) { - CMemoryCardSys::CARDStat stat = {}; + CMemoryCardSys::CardStat stat = {}; if (CMemoryCardSys::GetStatus(x0_cardPort, x100_mcFileInfos[0].second.GetFileNo(), stat) == ECardResult::READY) { @@ -421,7 +412,7 @@ void CMemoryCardDriver::StartFileWrite() { x14_error = EError::OK; x10_state = EState::FileWrite; - ECardResult result = x198_fileInfo->Write(); + ECardResult result = x198_fileInfo->WriteFile(); if (result != ECardResult::READY) UpdateFileWrite(result); } @@ -450,7 +441,7 @@ void CMemoryCardDriver::StartFileWriteTransactional() { x14_error = EError::OK; x10_state = EState::FileWriteTransactional; - ECardResult result = x198_fileInfo->Write(); + ECardResult result = x198_fileInfo->WriteFile(); if (result != ECardResult::READY) UpdateFileWriteTransactional(result); } @@ -658,7 +649,7 @@ void CMemoryCardDriver::UpdateFileWrite(ECardResult result) if (xferResult == ECardResult::READY) { x10_state = EState::Ready; - if (x198_fileInfo->Close() == ECardResult::READY) + if (x198_fileInfo->CloseFile() == ECardResult::READY) return; NoCardFound(); return; @@ -696,7 +687,7 @@ void CMemoryCardDriver::UpdateFileWriteTransactional(ECardResult result) if (xferResult == ECardResult::READY) { x10_state = EState::FileWriteTransactionalDone; - if (x198_fileInfo->Close() != ECardResult::READY) + if (x198_fileInfo->CloseFile() != ECardResult::READY) { NoCardFound(); return; @@ -768,7 +759,7 @@ void CMemoryCardDriver::InitializeFileInfo() x198_fileInfo->SetComment(comment); x198_fileInfo->LockBannerToken(x4_saveBanner, *g_SimplePool); - x198_fileInfo->LockIconToken(x8_saveIcon0, 2, *g_SimplePool); + x198_fileInfo->LockIconToken(x8_saveIcon0, kabufuda::EAnimationSpeed::Middle, *g_SimplePool); CMemoryOutStream w = x198_fileInfo->BeginMemoryOut(3004); @@ -825,7 +816,7 @@ void CMemoryCardDriver::HandleCardError(ECardResult result, EState state) void CMemoryCardDriver::Update() { - CMemoryCardSys::CardProbeResults result = CMemoryCardSys::CardProbe(x0_cardPort); + kabufuda::ProbeResults result = CMemoryCardSys::CardProbe(x0_cardPort); if (result.x0_error == ECardResult::NOCARD) { diff --git a/Runtime/MP1/CMemoryCardDriver.hpp b/Runtime/MP1/CMemoryCardDriver.hpp index ac27887dd..2edf53bfc 100644 --- a/Runtime/MP1/CMemoryCardDriver.hpp +++ b/Runtime/MP1/CMemoryCardDriver.hpp @@ -70,30 +70,22 @@ public: }; private: - struct CARDFileInfo - { - CMemoryCardSys::EMemoryCardPort x0_cardPort; - int x4_fileNo = -1; - int x8_offset; - int xc_length; - u16 iBlock; - }; struct SFileInfo { - CARDFileInfo x0_fileInfo; + CMemoryCardSys::CardFileHandle x0_fileInfo; std::string x14_name; std::vector x24_saveFileData; std::vector x34_saveData; - SFileInfo(CMemoryCardSys::EMemoryCardPort cardPort, const std::string& name); - CMemoryCardSys::ECardResult Open(); - CMemoryCardSys::ECardResult Close(); - CMemoryCardSys::EMemoryCardPort GetFileCardPort() const { return x0_fileInfo.x0_cardPort; } - int GetFileNo() const { return x0_fileInfo.x4_fileNo; } - CMemoryCardSys::ECardResult StartRead(); - CMemoryCardSys::ECardResult TryFileRead(); - CMemoryCardSys::ECardResult FileRead(); - CMemoryCardSys::ECardResult GetSaveDataOffset(u32& offOut); + SFileInfo(kabufuda::ECardSlot cardPort, const std::string& name); + kabufuda::ECardResult Open(); + kabufuda::ECardResult Close(); + kabufuda::ECardSlot GetFileCardPort() const { return x0_fileInfo.slot; } + int GetFileNo() const { return x0_fileInfo->getFileNo(); } + kabufuda::ECardResult StartRead(); + kabufuda::ECardResult TryFileRead(); + kabufuda::ECardResult FileRead(); + kabufuda::ECardResult GetSaveDataOffset(u32& offOut); }; struct SSaveHeader @@ -129,7 +121,7 @@ private: BadFile }; - CMemoryCardSys::EMemoryCardPort x0_cardPort; + kabufuda::ECardSlot x0_cardPort; ResId x4_saveBanner; ResId x8_saveIcon0; ResId xc_saveIcon1; @@ -148,7 +140,7 @@ private: bool x19d_doImportPersistent; public: - CMemoryCardDriver(CMemoryCardSys::EMemoryCardPort cardPort, ResId saveBanner, + CMemoryCardDriver(kabufuda::ECardSlot cardPort, ResId saveBanner, ResId saveIcon0, ResId saveIcon1, bool importPersistent); void NoCardFound(); @@ -176,24 +168,24 @@ public: void StartCardFormat(); // 37 void UpdateCardProbe(); // 25 - void UpdateMountCard(CMemoryCardSys::ECardResult result); // 26 - void UpdateCardCheck(CMemoryCardSys::ECardResult result); // 27 - void UpdateFileDeleteBad(CMemoryCardSys::ECardResult result); // 28 - void UpdateFileRead(CMemoryCardSys::ECardResult result); // 29 - void UpdateFileDeleteAlt(CMemoryCardSys::ECardResult result); // 30 - void UpdateFileCreate(CMemoryCardSys::ECardResult result); // 31 - void UpdateFileWrite(CMemoryCardSys::ECardResult result); // 32 - void UpdateFileCreateTransactional(CMemoryCardSys::ECardResult result); // 33 - void UpdateFileWriteTransactional(CMemoryCardSys::ECardResult result); // 34 - void UpdateFileDeleteAltTransactional(CMemoryCardSys::ECardResult result); // 35 - void UpdateFileRenameBtoA(CMemoryCardSys::ECardResult result); // 36 - void UpdateCardFormat(CMemoryCardSys::ECardResult result); // 37 + void UpdateMountCard(kabufuda::ECardResult result); // 26 + void UpdateCardCheck(kabufuda::ECardResult result); // 27 + void UpdateFileDeleteBad(kabufuda::ECardResult result); // 28 + void UpdateFileRead(kabufuda::ECardResult result); // 29 + void UpdateFileDeleteAlt(kabufuda::ECardResult result); // 30 + void UpdateFileCreate(kabufuda::ECardResult result); // 31 + void UpdateFileWrite(kabufuda::ECardResult result); // 32 + void UpdateFileCreateTransactional(kabufuda::ECardResult result); // 33 + void UpdateFileWriteTransactional(kabufuda::ECardResult result); // 34 + void UpdateFileDeleteAltTransactional(kabufuda::ECardResult result); // 35 + void UpdateFileRenameBtoA(kabufuda::ECardResult result); // 36 + void UpdateCardFormat(kabufuda::ECardResult result); // 37 void ClearFileInfo() { x198_fileInfo.reset(); } void InitializeFileInfo(); void WriteBackupBuf(); bool GetCardFreeBytes(); - void HandleCardError(CMemoryCardSys::ECardResult result, EState state); + void HandleCardError(kabufuda::ECardResult result, EState state); void Update(); void ClearError() { x14_error = EError::OK; } diff --git a/Runtime/MP1/CSaveUI.cpp b/Runtime/MP1/CSaveUI.cpp index f1833f204..32bc2bb82 100644 --- a/Runtime/MP1/CSaveUI.cpp +++ b/Runtime/MP1/CSaveUI.cpp @@ -76,7 +76,7 @@ CIOWin::EMessageReturn CSaveUI::Update(float dt) if (x6c_cardDriver->x10_state == EState::NoCard) { - auto res = CMemoryCardSys::CardProbe(CMemoryCardSys::EMemoryCardPort::SlotA); + auto res = CMemoryCardSys::CardProbe(kabufuda::ECardSlot::SlotA); if (res.x0_error == CMemoryCardSys::ECardResult::READY || res.x0_error == CMemoryCardSys::ECardResult::WRONGDEVICE) ResetCardDriver(); @@ -257,7 +257,7 @@ CSaveUI::CSaveUI(u32 instIdx, u64 serial) std::unique_ptr CSaveUI::ConstructCardDriver(bool importState) { - return std::make_unique(CMemoryCardSys::EMemoryCardPort::SlotA, + return std::make_unique(kabufuda::ECardSlot::SlotA, g_ResFactory->GetResourceIdByName("TXTR_SaveBanner")->id, g_ResFactory->GetResourceIdByName("TXTR_SaveIcon0")->id, g_ResFactory->GetResourceIdByName("TXTR_SaveIcon1")->id, importState); diff --git a/kabufuda b/kabufuda index 31029767c..223ea9a56 160000 --- a/kabufuda +++ b/kabufuda @@ -1 +1 @@ -Subproject commit 31029767c8238d0cd9f301153a7196150a45c25d +Subproject commit 223ea9a56ebc8ad7e03a2b920dbdc9d621cda551 From 563ff28848440429a19d25e01c447799ee76afbc Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Wed, 28 Dec 2016 08:28:50 -1000 Subject: [PATCH 2/2] Move KABUFUDA_INCLUDE_DIR reference --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d6138ce8..6998326b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,9 +97,10 @@ add_definitions(-DZE_ATHENA_TYPES=1) set(ZEUS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/specter/zeus/include) include_directories(${ATHENA_INCLUDE_DIR} ${LOGVISOR_INCLUDE_DIR} ${HECL_INCLUDE_DIR} ${NOD_INCLUDE_DIR} ${ZEUS_INCLUDE_DIR} ${BOO_INCLUDE_DIR} ${AMUSE_INCLUDE_DIR} - ${SPECTER_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ${KABUFUDA_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + ${SPECTER_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(DataSpec) add_subdirectory(kabufuda) +include_directories(${KABUFUDA_INCLUDE_DIR}) add_subdirectory(Editor) set(CLIENT_SOURCES