Additional memory card imps

This commit is contained in:
Jack Andersen 2016-12-23 14:45:51 -10:00
parent 513d283bee
commit a7322e8916
8 changed files with 234 additions and 54 deletions

View File

@ -39,7 +39,8 @@ public:
static OSTime ToWiiTime(std::chrono::system_clock::time_point time);
static std::chrono::system_clock::time_point FromWiiTime(OSTime wiiTime);
static OSCalendarTime ToCalendarTime(OSTime time);
static OSCalendarTime ToCalendarTime(OSTime time) { return ToCalendarTime(FromWiiTime(time)); }
static OSCalendarTime ToCalendarTime(std::chrono::system_clock::time_point time);
};
}

View File

@ -24,45 +24,88 @@ const char* CBasics::Stringize(const char* fmt, ...)
const u64 CBasics::SECONDS_TO_2000 = 946684800LL;
const u64 CBasics::TICKS_PER_SECOND = 60750000LL;
#ifndef _WIN32
static struct tm* localtime_r(const time_t& time, struct tm& timeSt, long& gmtOff)
{
auto ret = localtime_r(&time, &timeSt);
if (!ret)
return nullptr;
gmtOff = ret->tm_gmtoff;
return ret;
}
#else
static struct tm* localtime_r(const time_t& time, struct tm& timeSt, long& gmtOff)
{
struct tm _gmSt;
auto reta = localtime_s(&timeSt, &time);
auto retb = gmtime_s(&_gmSt, &time);
if (reta || retb)
return nullptr;
gmtOff = mktime(&timeSt) - mktime(&_gmSt);
return &timeSt;
}
#endif
OSTime CBasics::ToWiiTime(std::chrono::system_clock::time_point time)
{
time_t sysTime, tzDiff;
struct tm* gmTime;
auto sec = std::chrono::time_point_cast<std::chrono::seconds>(time);
auto us = std::chrono::duration_cast<std::chrono::microseconds>((time - sec)).count();
time_t sysTime = std::chrono::system_clock::to_time_t(sec);
sysTime = std::chrono::system_clock::to_time_t(time);
// Account for DST where needed
gmTime = localtime(&sysTime);
if (!gmTime)
struct tm _timeSt;
long gmtOff;
struct tm* timeSt = localtime_r(sysTime, _timeSt, gmtOff);
if (!timeSt)
return 0;
// Lazy way to get local time in sec
gmTime = gmtime(&sysTime);
tzDiff = sysTime - mktime(gmTime);
return OSTime(TICKS_PER_SECOND * ((sysTime + tzDiff) - SECONDS_TO_2000));
/* Returning local */
return OSTime(TICKS_PER_SECOND * ((sysTime + gmtOff) - SECONDS_TO_2000) +
us * TICKS_PER_SECOND / 1000000);
}
std::chrono::system_clock::time_point CBasics::FromWiiTime(OSTime wiiTime)
{
time_t time = SECONDS_TO_2000 + wiiTime / TICKS_PER_SECOND;
auto div = std::lldiv(SECONDS_TO_2000 + wiiTime, TICKS_PER_SECOND);
time_t time = time_t(div.quot);
time_t sysTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
// Account for DST where needed
struct tm* gmTime = localtime(&sysTime);
if (!gmTime)
struct tm _timeSt;
long gmtOff;
struct tm* timeSt = localtime_r(sysTime, _timeSt, gmtOff);
if (!timeSt)
return std::chrono::system_clock::from_time_t(0);
// Lazy way to get local time in sec
gmTime = gmtime(&sysTime);
time_t tzDiff = sysTime - mktime(gmTime);
return std::chrono::system_clock::from_time_t(time - tzDiff);
/* Returning GMT */
return std::chrono::system_clock::from_time_t(time - gmtOff) +
std::chrono::microseconds(div.rem * 1000000 / TICKS_PER_SECOND);
}
OSCalendarTime CBasics::ToCalendarTime(OSTime time)
OSCalendarTime CBasics::ToCalendarTime(std::chrono::system_clock::time_point time)
{
OSCalendarTime ret = {};
/* TODO: Finsh */
OSCalendarTime ret;
auto sec = std::chrono::time_point_cast<std::chrono::seconds>(time);
auto us = std::chrono::duration_cast<std::chrono::microseconds>((time - sec)).count();
time_t sysTime = std::chrono::system_clock::to_time_t(sec);
struct tm _timeSt;
long gmtOff;
struct tm* timeSt = localtime_r(sysTime, _timeSt, gmtOff);
if (!timeSt)
return {};
ret.x0_sec = timeSt->tm_sec;
ret.x4_min = timeSt->tm_min;
ret.x8_hour = timeSt->tm_hour;
ret.xc_mday = timeSt->tm_mday;
ret.x10_mon = timeSt->tm_mon;
ret.x14_year = timeSt->tm_year + 1900;
ret.x18_wday = timeSt->tm_wday;
ret.x1c_yday = timeSt->tm_yday;
auto div = std::ldiv(us, 1000);
ret.x20_msec = div.quot;
ret.x24_usec = div.rem;
return ret;
}

View File

@ -189,9 +189,9 @@ void CMemoryCardSys::CCardFileInfo::BuildCardBuffer()
CMemoryOutStream w(x104_cardBuffer.data(), x104_cardBuffer.size());
w.writeUint32Big(0);
char name[64];
strncpy(name, x28_name2.data(), 64);
w.writeBytes(name, 64);
char comment[64];
strncpy(comment, x28_comment.data(), 64);
w.writeBytes(comment, 64);
WriteBannerData(w);
WriteIconData(w);
memmove(x104_cardBuffer.data() + bannerSz, xf4_saveBuffer.data(), xf4_saveBuffer.size());

View File

@ -172,8 +172,8 @@ public:
EStatus x0_status = EStatus::Standby;
CARDFileInfo x4_info;
std::string x18_name;
std::string x28_name2;
std::string x18_fileName;
std::string x28_comment;
ResId x3c_bannerTex = -1;
std::experimental::optional<TLockedToken<CTexture>> x40_bannerTok;
rstl::reserved_vector<Icon, 8> x50_iconToks;
@ -183,7 +183,7 @@ public:
CVParamTransfer m_texParam = {new TObjOwnerParam<u32>(SBIG('OTEX'))};
CCardFileInfo(EMemoryCardPort port, const std::string& name)
: x4_info(port), x18_name(name) {}
: x4_info(port), x18_fileName(name) {}
void LockBannerToken(ResId bannerTxtr, CSimplePool& sp);
void LockIconToken(ResId iconTxtr, u32 speed, CSimplePool& sp);
@ -195,11 +195,18 @@ public:
void BuildCardBuffer();
void WriteBannerData(CMemoryOutStream& out) const;
void WriteIconData(CMemoryOutStream& out) const;
void SetComment(const std::string& c) { x28_comment = c; }
ECardResult PumpCardTransfer();
ECardResult GetStatus(CARDStat& stat) const;
ECardResult CreateFile();
ECardResult Write();
ECardResult Close();
CMemoryOutStream BeginMemoryOut(u32 sz)
{
xf4_saveBuffer.resize(sz);
return CMemoryOutStream(xf4_saveBuffer.data(), sz);
}
};
static CardProbeResults CardProbe(EMemoryCardPort port);

View File

@ -226,9 +226,9 @@ CGameState::GameFileStateInfo* CMemoryCardDriver::GetGameFileStateInfo(int idx)
CMemoryCardDriver::SSaveHeader CMemoryCardDriver::LoadSaveHeader(CMemoryInStream& in)
{
SSaveHeader ret;
ret.x0_ = in.readUint32Big();
ret.x0_version = in.readUint32Big();
for (int i=0 ; i<3 ; ++i)
ret.x4_[i] = in.readBool();
ret.x4_savePresent[i] = in.readBool();
return ret;
}
@ -655,10 +655,28 @@ void CMemoryCardDriver::GoTo29()
Case29(result);
}
void CMemoryCardDriver::GoTo31()
{
x14_error = EError::Zero;
x10_state = EState::ThirtyOne;
if (x18_cardFreeBytes < 8192 || x1c_cardFreeFiles < 2)
{
x10_state = EState::Eighteen;
x14_error = EError::Five;
return;
}
x198_fileInfo = std::make_unique<CMemoryCardSys::CCardFileInfo>(x0_cardPort, SaveFileNames[x194_fileIdx]);
InitializeFileInfo();
ECardResult result = x198_fileInfo->CreateFile();
if (result != ECardResult::CARD_RESULT_READY)
Case31(result);
}
void CMemoryCardDriver::GoTo32()
{
x14_error = EError::Zero;
x10_state = EState::Write;
x10_state = EState::ThirtyTwo;
ECardResult result = x198_fileInfo->Write();
if (result != ECardResult::CARD_RESULT_READY)
Case32(result);
@ -667,7 +685,7 @@ void CMemoryCardDriver::GoTo32()
void CMemoryCardDriver::GoTo33()
{
x14_error = EError::Zero;
x10_state = EState::ThirtyThree;
x10_state = EState::FileBuild;
ClearFileInfo();
if (x18_cardFreeBytes < 8192 || !x1c_cardFreeFiles)
{
@ -686,7 +704,7 @@ void CMemoryCardDriver::GoTo33()
void CMemoryCardDriver::GoTo34()
{
x14_error = EError::Zero;
x10_state = EState::ThirtyFour;
x10_state = EState::FileWrite;
ECardResult result = x198_fileInfo->Write();
if (result != ECardResult::CARD_RESULT_READY)
Case34(result);
@ -707,7 +725,7 @@ void CMemoryCardDriver::GoTo36()
if (x194_fileIdx == 1)
{
x14_error = EError::Zero;
x10_state = EState::ThirtySix;
x10_state = EState::FileRename;
ECardResult result = CMemoryCardSys::Rename(x0_cardPort,
SaveFileNames[x194_fileIdx],
SaveFileNames[!bool(x194_fileIdx)]);
@ -733,7 +751,31 @@ void CMemoryCardDriver::GoTo37()
void CMemoryCardDriver::InitializeFileInfo()
{
ExportPersistentOptions();
/* TODO: Finish */
OSCalendarTime time = CBasics::ToCalendarTime(std::chrono::system_clock::now());
char timeString[32];
snprintf(timeString, 32, "%02d.%02d.%02d %02d:%02d",
time.x10_mon + 1, time.xc_mday, time.x14_year % 100,
time.x8_hour, time.x4_min);
std::string comment("Metroid Prime ");
comment += timeString;
x198_fileInfo->SetComment(comment);
x198_fileInfo->LockBannerToken(x4_saveBanner, *g_SimplePool);
x198_fileInfo->LockIconToken(x8_saveIcon0, 2, *g_SimplePool);
CMemoryOutStream w = x198_fileInfo->BeginMemoryOut(3004);
SSaveHeader header;
for (int i=0 ; i<3 ; ++i)
header.x4_savePresent[i] = xe4_fileSlots[i].operator bool();
header.DoPut(w);
w.writeBytes(x30_systemData, 174);
for (int i=0 ; i<3 ; ++i)
if (xe4_fileSlots[i])
xe4_fileSlots[i]->DoPut(w);
}
void CMemoryCardDriver::WriteBackupBuf()
@ -822,19 +864,19 @@ void CMemoryCardDriver::Update()
case EState::ThirtyOne:
Case31(resultCode);
break;
case EState::Write:
case EState::ThirtyTwo:
Case32(resultCode);
break;
case EState::ThirtyThree:
case EState::FileBuild:
Case33(resultCode);
break;
case EState::ThirtyFour:
case EState::FileWrite:
Case34(resultCode);
break;
case EState::ThirtyFive:
Case35(resultCode);
break;
case EState::ThirtySix:
case EState::FileRename:
Case36(resultCode);
break;
case EState::CardFormat:

View File

@ -47,11 +47,11 @@ public:
TwentyNine = 29,
Thirty = 30,
ThirtyOne = 31,
Write = 32,
ThirtyThree = 33,
ThirtyFour = 34,
ThirtyTwo = 32,
FileBuild = 33,
FileWrite = 34,
ThirtyFive = 35,
ThirtySix = 36,
FileRename = 36,
CardFormat = 37
};
@ -98,8 +98,14 @@ private:
struct SSaveHeader
{
u32 x0_;
u32 x4_[3];
u32 x0_version = 0;
bool x4_savePresent[3];
void DoPut(CMemoryOutStream& out) const
{
out.writeUint32Big(x0_version);
for (int i=0 ; i<3 ; ++i)
out.writeBool(x4_savePresent[i]);
}
};
struct SGameFileSlot
@ -109,6 +115,10 @@ private:
SGameFileSlot();
SGameFileSlot(CMemoryInStream& in);
void InitializeFromGameState();
void DoPut(CMemoryOutStream& w) const
{
w.writeBytes(x0_saveBuffer, 940);
}
};
CMemoryCardSys::EMemoryCardPort x0_cardPort;
@ -164,6 +174,7 @@ public:
void GoTo17();
void GoTo28();
void GoTo29();
void GoTo31();
void GoTo32();
void GoTo33();
void GoTo34();

View File

@ -12,9 +12,84 @@ namespace MP1
{
using EState = CMemoryCardDriver::EState;
using EError = CMemoryCardDriver::EError;
void CSaveUI::ResetCardDriver()
{
x92_ = false;
x6c_cardDriver.reset();
bool flag = (x0_instIdx == 0 && !x90_needsDriverReset);
x6c_cardDriver = ConstructCardDriver(flag);
x6c_cardDriver->FinishedLoading();
x10_uiType = UIType::Zero;
FinishedLoading();
}
CIOWin::EMessageReturn CSaveUI::Update(float dt)
{
if (PumpLoad())
return CIOWin::EMessageReturn::Normal;
x50_loadedFrame->Update(dt);
x6c_cardDriver->Update();
if (x6c_cardDriver->x10_state == EState::RuntimeBackup)
{
if (x90_needsDriverReset)
{
ResetCardDriver();
x90_needsDriverReset = false;
}
else
x80_iowRet = CIOWin::EMessageReturn::Exit;
}
else if (x6c_cardDriver->x10_state == EState::SelectCardFile && x10_uiType != UIType::Fourteen)
{
if (x6c_cardDriver->x28_cardSerial && x8_serial)
{
if (x93_secondaryInst)
{
x10_uiType = UIType::Fourteen;
x91_ = true;
}
else
{
x8_serial = x6c_cardDriver->x28_cardSerial;
x6c_cardDriver->GoTo17();
}
}
}
else if (x6c_cardDriver->x10_state == EState::Ready)
{
if (x90_needsDriverReset)
x6c_cardDriver->GoTo33();
}
if (x80_iowRet != CIOWin::EMessageReturn::Normal)
return x80_iowRet;
UIType oldTp = x10_uiType;
x10_uiType = SelectUIType();
if (oldTp == x10_uiType || x91_)
FinishedLoading();
if (x6c_cardDriver->x10_state == EState::NoCard)
{
auto res = CMemoryCardSys::CardProbe(CMemoryCardSys::EMemoryCardPort::SlotA);
if (res.x0_error == CMemoryCardSys::ECardResult::CARD_RESULT_READY ||
res.x0_error == CMemoryCardSys::ECardResult::CARD_RESULT_WRONGDEVICE)
ResetCardDriver();
}
else if (x6c_cardDriver->x10_state == EState::CardFormatted)
{
ResetCardDriver();
}
else if (x6c_cardDriver->x10_state == EState::Seventeen &&
x6c_cardDriver->x14_error == EError::Eight)
{
x6c_cardDriver->GoTo31();
}
return CIOWin::EMessageReturn::Normal;
}
@ -152,8 +227,8 @@ void* CSaveUI::GetGameData(int idx) const
return nullptr;
}
CSaveUI::CSaveUI(u32 instIdx, u32 a, u32 b)
: x0_instIdx(instIdx), x8_a(a), xc_b(b)
CSaveUI::CSaveUI(u32 instIdx, u64 serial)
: x0_instIdx(instIdx), x8_serial(serial)
{
x14_txtrSaveBanner = g_SimplePool->GetObj("TXTR_SaveBanner");
x20_txtrSaveIcon0 = g_SimplePool->GetObj("TXTR_SaveIcon0");

View File

@ -59,8 +59,7 @@ public:
private:
u32 x0_instIdx;
u32 x8_a;
u32 xc_b;
u64 x8_serial;
UIType x10_uiType = UIType::Zero;
TLockedToken<CTexture> x14_txtrSaveBanner;
TLockedToken<CTexture> x20_txtrSaveIcon0;
@ -76,15 +75,17 @@ private:
CGuiTextPane* x68_textpane_choice3;
std::unique_ptr<CMemoryCardDriver> x6c_cardDriver;
std::vector<TLockedToken<CSaveWorld>> x70_saveWorlds;
u32 x80_ = 0;
CIOWin::EMessageReturn x80_iowRet = CIOWin::EMessageReturn::Normal;
u32 x84_navConfirmSfx = 1460;
u32 x88_navMoveSfx = 1461;
u32 x8c_navBackSfx = 1459;
bool x90_ = false;
bool x90_needsDriverReset = false;
bool x91_ = false;
bool x92_ = false;
bool x93_secondaryInst;
void ResetCardDriver();
public:
static std::unique_ptr<CMemoryCardDriver> ConstructCardDriver(bool flag);
CIOWin::EMessageReturn Update(float dt);
@ -101,7 +102,7 @@ public:
void EraseGame(int idx);
void* GetGameData(int idx) const;
UIType GetUIType() const { return x10_uiType; }
CSaveUI(u32 inst, u32 a, u32 b);
CSaveUI(u32 inst, u64 serial);
};
}