From 9ea7cee23c527ffe819e0e7f8f27c5f19db4d13c Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Fri, 3 Feb 2017 17:46:12 -1000 Subject: [PATCH 1/5] Memory card bug fixes --- DataSpec/DNAMP1/FRME.cpp | 4 ++- Runtime/CMemoryCardSys.cpp | 21 +++++++++---- Runtime/CMemoryCardSys.hpp | 2 ++ Runtime/CMemoryCardSysOSX.cpp | 26 ++++++++++++++++ Runtime/Graphics/CTextureBoo.cpp | 10 ++++--- Runtime/IOStreams.cpp | 28 +++++++++++++----- Runtime/IOStreams.hpp | 25 +++++++--------- Runtime/MP1/CFrontEndUI.cpp | 20 +++++-------- Runtime/MP1/CFrontEndUI.hpp | 2 -- Runtime/MP1/CMemoryCardDriver.cpp | 26 ++++++---------- Runtime/MP1/CMemoryCardDriver.hpp | 4 +-- Runtime/MP1/CSaveUI.cpp | 49 +++++++++++++++++++------------ hecl | 2 +- kabufuda | 2 +- 14 files changed, 133 insertions(+), 88 deletions(-) diff --git a/DataSpec/DNAMP1/FRME.cpp b/DataSpec/DNAMP1/FRME.cpp index 66a8ffafc..3ab077610 100644 --- a/DataSpec/DNAMP1/FRME.cpp +++ b/DataSpec/DNAMP1/FRME.cpp @@ -365,6 +365,7 @@ bool FRME::Extract(const SpecBase &dataSpec, "bg_node = bpy.context.scene.world.node_tree.nodes['Background']\n", pakRouter.getBestEntryName(entry).c_str()); + int pIdx = 0; for (const FRME::Widget& w : frme.widgets) { os << "binding = None\n" @@ -532,6 +533,7 @@ bool FRME::Extract(const SpecBase &dataSpec, } os.format("frme_obj = bpy.data.objects.new(name='%s', object_data=binding)\n" + "frme_obj.pass_index = %d\n" "parentName = '%s'\n" "frme_obj.retro_widget_type = 'RETRO_%s'\n" "frme_obj.retro_widget_use_anim_controller = %s\n" @@ -546,7 +548,7 @@ bool FRME::Extract(const SpecBase &dataSpec, " frme_obj.retro_widget_parent = parentName\n" "else:\n" " frme_obj.parent = bpy.data.objects[parentName]\n", - w.header.name.c_str(), w.header.parent.c_str(), + w.header.name.c_str(), pIdx++, w.header.parent.c_str(), w.type.toString().c_str(), w.header.useAnimController ? "True" : "False", w.header.defaultVisible ? "True" : "False", diff --git a/Runtime/CMemoryCardSys.cpp b/Runtime/CMemoryCardSys.cpp index 8449aa239..00e1e360f 100644 --- a/Runtime/CMemoryCardSys.cpp +++ b/Runtime/CMemoryCardSys.cpp @@ -79,9 +79,6 @@ const CSaveWorldMemory& CMemoryCardSys::GetSaveWorldMemory(ResId wldId) const CMemoryCardSys::CMemoryCardSys() { - g_CardImagePaths[0] = ResolveDolphinCardPath(kabufuda::ECardSlot::SlotA); - g_CardImagePaths[1] = ResolveDolphinCardPath(kabufuda::ECardSlot::SlotB); - x0_hints = g_SimplePool->GetObj("HINT_Hints"); xc_memoryWorlds.reserve(16); x1c_worldInter.emplace(); @@ -340,6 +337,7 @@ ECardResult CMemoryCardSys::CCardFileInfo::WriteFile() { BuildCardBuffer(); //DCStoreRange(x104_cardBuffer.data(), x104_cardBuffer.size()); + x0_status = EStatus::Transferring; return CMemoryCardSys::WriteFile(m_handle, x104_cardBuffer.data(), x104_cardBuffer.size(), 0); } @@ -350,6 +348,9 @@ ECardResult CMemoryCardSys::CCardFileInfo::CloseFile() kabufuda::ProbeResults CMemoryCardSys::CardProbe(kabufuda::ECardSlot port) { + g_CardImagePaths[0] = ResolveDolphinCardPath(kabufuda::ECardSlot::SlotA); + g_CardImagePaths[1] = ResolveDolphinCardPath(kabufuda::ECardSlot::SlotB); + kabufuda::ProbeResults res = kabufuda::Card::probeCardFile(g_CardImagePaths[int(port)]); g_OpResults[int(port)] = res.x0_error; return res; @@ -358,13 +359,12 @@ kabufuda::ProbeResults CMemoryCardSys::CardProbe(kabufuda::ECardSlot port) ECardResult CMemoryCardSys::MountCard(kabufuda::ECardSlot port) { kabufuda::Card& card = g_CardStates[int(port)]; - card.commit(); + card.close(); card = kabufuda::Card(g_CardImagePaths[int(port)], "GM8E", "01"); ECardResult result = card.getError(); g_OpResults[int(port)] = result; if (result == ECardResult::READY) return ECardResult::READY; - card = kabufuda::Card(); return result; } @@ -570,12 +570,12 @@ ECardResult CMemoryCardSys::Rename(kabufuda::ECardSlot port, const char* oldName ECardResult CMemoryCardSys::FormatCard(kabufuda::ECardSlot port) { kabufuda::Card& card = g_CardStates[int(port)]; + card.format(port); if (CardResult err = card.getError()) { g_OpResults[int(port)] = err; return err; } - card.format(port); g_OpResults[int(port)] = ECardResult::READY; return ECardResult::READY; } @@ -586,6 +586,15 @@ void CMemoryCardSys::CommitToDisk(kabufuda::ECardSlot port) card.commit(); } +kabufuda::SystemString CMemoryCardSys::CreateDolphinCard(kabufuda::ECardSlot slot) +{ + kabufuda::SystemString path = _CreateDolphinCard(slot); + CardProbe(slot); + MountCard(slot); + FormatCard(slot); + return path; +} + void CMemoryCardSys::Shutdown() { UnmountCard(kabufuda::ECardSlot::SlotA); diff --git a/Runtime/CMemoryCardSys.hpp b/Runtime/CMemoryCardSys.hpp index a4be19e0b..fc625aeeb 100644 --- a/Runtime/CMemoryCardSys.hpp +++ b/Runtime/CMemoryCardSys.hpp @@ -66,6 +66,8 @@ class CMemoryCardSys public: static kabufuda::SystemString ResolveDolphinCardPath(kabufuda::ECardSlot slot); + static kabufuda::SystemString CreateDolphinCard(kabufuda::ECardSlot slot); + static kabufuda::SystemString _CreateDolphinCard(kabufuda::ECardSlot slot); using ECardResult = kabufuda::ECardResult; struct CardResult diff --git a/Runtime/CMemoryCardSysOSX.cpp b/Runtime/CMemoryCardSysOSX.cpp index 87b6c13cc..f8e80f6c7 100644 --- a/Runtime/CMemoryCardSysOSX.cpp +++ b/Runtime/CMemoryCardSysOSX.cpp @@ -20,4 +20,30 @@ kabufuda::SystemString CMemoryCardSys::ResolveDolphinCardPath(kabufuda::ECardSlo return path; } +kabufuda::SystemString CMemoryCardSys::_CreateDolphinCard(kabufuda::ECardSlot slot) +{ + const char* home = getenv("HOME"); + if (!home) + return {}; + + kabufuda::SystemString path = home; + path += "/Library/Application Support/Dolphin/GC"; + if (hecl::RecursiveMakeDir(path.c_str()) < 0) + return {}; + + path += hecl::Format("/MemoryCard%c.USA.raw", + slot == kabufuda::ECardSlot::SlotA ? 'A' : 'B'); + FILE* fp = hecl::Fopen(path.c_str(), "wb"); + if (!fp) + return {}; + /* + const u32 fword = 0xffffffff; + for (int i=0 ; i<0x1000000/4 ; ++i) + fwrite(&fword, 1, 4, fp); + */ + fclose(fp); + + return path; +} + } diff --git a/Runtime/Graphics/CTextureBoo.cpp b/Runtime/Graphics/CTextureBoo.cpp index b1fdc3dab..b3e8b3ae4 100644 --- a/Runtime/Graphics/CTextureBoo.cpp +++ b/Runtime/Graphics/CTextureBoo.cpp @@ -891,7 +891,7 @@ std::unique_ptr CTexture::BuildMemoryCardTex(u32& sizeOut, ETexelFormat& f int baseX = bx * 4; for (int y=0 ; y<4 ; ++y) { - const RGBA8* source = sourceMip + (baseY + y) * w + baseX; + const RGBA8* source = sourceMip + (x6_h - (baseY + y) - 1) * w + baseX; for (int x=0 ; x<4 ; ++x) { if (source[x].a == 0xff) @@ -931,8 +931,10 @@ std::unique_ptr CTexture::BuildMemoryCardTex(u32& sizeOut, ETexelFormat& f for (int i=0; i<256; ++i) { u16& color = paletteColors[i]; - if (i < nentries) + if (i >= nentries) + { color = 0; + } else { const RGBA8& colorIn = paletteTexels[i]; @@ -940,7 +942,7 @@ std::unique_ptr CTexture::BuildMemoryCardTex(u32& sizeOut, ETexelFormat& f { color = hecl::SBig(u16((colorIn.r >> 3 << 10) | (colorIn.g >> 3 << 5) | - (colorIn.b >> 3))); + (colorIn.b >> 3) | 0x8000)); } else { @@ -962,7 +964,7 @@ std::unique_ptr CTexture::BuildMemoryCardTex(u32& sizeOut, ETexelFormat& f int baseX = bx * 8; for (int y=0 ; y<4 ; ++y) { - const u8* source = sourceMip + (baseY + y) * w + baseX; + const u8* source = sourceMip + (x6_h - (baseY + y) - 1) * w + baseX; for (int x=0 ; x<8 ; ++x) *texel++ = source[x]; } diff --git a/Runtime/IOStreams.cpp b/Runtime/IOStreams.cpp index 4bd961cba..775ce2bb7 100644 --- a/Runtime/IOStreams.cpp +++ b/Runtime/IOStreams.cpp @@ -30,9 +30,9 @@ s32 CBitStreamReader::ReadEncoded(u32 bitCount) baseVal = (baseVal & (x1c_val >> (32 - x20_bitOffset))) << diff; x20_bitOffset = 0; - u32 bit = diff & 7; - u32 count = (diff >> 3) + ((-bit | bit) >> 31); - readUBytesToBuf(&x1c_val, count); + auto pos = std::div(diff, 8); + if (pos.rem) ++pos.quot; + readUBytesToBuf(&x1c_val, pos.quot); /* The game uses Big Endian, which doesn't work for us */ /* Little Endian sucks */ athena::utility::BigUint32(x1c_val); @@ -42,7 +42,7 @@ s32 CBitStreamReader::ReadEncoded(u32 bitCount) baseVal2 = (1 << diff) - 1; ret = baseVal | (baseVal2 & (x1c_val >> (32 - diff))) << x20_bitOffset; - x20_bitOffset = (count << 3) - diff; + x20_bitOffset = (pos.quot << 3) - diff; x1c_val <<= diff; } @@ -71,9 +71,9 @@ void CBitStreamWriter::WriteEncoded(u32 val, u32 bitCount) x18_bitOffset = 0; u32 tmp = x14_val; athena::utility::BigUint32(tmp); - u32 bit = (32 - x18_bitOffset) & 7; - u32 count = ((32 - x18_bitOffset) >> 3) + ((-bit | bit) >> 31); - writeBytes(&tmp, count); + auto pos = std::div(32 - x18_bitOffset, 8); + if (pos.rem) ++pos.quot; + writeBytes(&tmp, pos.quot); u32 rem = 32 - diff; baseVal = -1; @@ -85,6 +85,20 @@ void CBitStreamWriter::WriteEncoded(u32 val, u32 bitCount) } } +void CBitStreamWriter::Flush() +{ + if (x18_bitOffset && x18_bitOffset < 0x20) + { + u32 tmp = x14_val; + athena::utility::BigUint32(tmp); + auto pos = std::div(32 - x18_bitOffset, 8); + if (pos.rem) ++pos.quot; + writeBytes(&tmp, pos.quot); + x18_bitOffset = 32; + x14_val = 0; + } +} + class CZipSupport { public: diff --git a/Runtime/IOStreams.hpp b/Runtime/IOStreams.hpp index 53ce54850..502a9ecb6 100644 --- a/Runtime/IOStreams.hpp +++ b/Runtime/IOStreams.hpp @@ -13,7 +13,7 @@ namespace urde using CInputStream = athena::io::IStreamReader; using COutputStream = athena::io::IStreamWriter; -struct CBitStreamReader : athena::io::MemoryCopyReader +struct CBitStreamReader : athena::io::MemoryReader { u32 x1c_val = 0; u32 x20_bitOffset = 0; @@ -31,26 +31,21 @@ public: } CBitStreamReader(const void* data, atUint64 length) - : MemoryCopyReader(data, length) - { - } - - CBitStreamReader(const std::string& filename) - : MemoryCopyReader(filename) + : MemoryReader(data, length) { } atUint64 readUBytesToBuf(void *buf, atUint64 len) { x20_bitOffset = 0; - atUint64 tmp = MemoryCopyReader::readUBytesToBuf(buf, len); + atUint64 tmp = MemoryReader::readUBytesToBuf(buf, len); return tmp; } s32 ReadEncoded(u32 key); }; -class CBitStreamWriter : public athena::io::MemoryCopyWriter +class CBitStreamWriter : public athena::io::MemoryWriter { private: u32 x14_val = 0; @@ -59,21 +54,21 @@ public: static inline u32 GetBitCount(u32 maxVal) { return CBitStreamReader::GetBitCount(maxVal); } CBitStreamWriter(atUint8* data = nullptr, atUint64 length=0x10) - : MemoryCopyWriter(data, length) - {} - - CBitStreamWriter(const std::string& filename) - : MemoryCopyWriter(filename) + : MemoryWriter(data, length) {} void writeUBytes(const atUint8 *data, atUint64 len) { x14_val = 0; x18_bitOffset = 0x20; - MemoryCopyWriter::writeUBytes(data, len); + MemoryWriter::writeUBytes(data, len); } void WriteEncoded(u32 val, u32 bitCount); + + void Flush(); + + ~CBitStreamWriter() { Flush(); } }; using CMemoryInStream = athena::io::MemoryReader; diff --git a/Runtime/MP1/CFrontEndUI.cpp b/Runtime/MP1/CFrontEndUI.cpp index 01c83a4ae..4f74367c4 100644 --- a/Runtime/MP1/CFrontEndUI.cpp +++ b/Runtime/MP1/CFrontEndUI.cpp @@ -184,6 +184,8 @@ void CFrontEndUI::SNewFileSelectFrame::Update(float dt) CFrontEndUI::SNewFileSelectFrame::EAction CFrontEndUI::SNewFileSelectFrame::ProcessUserInput(const CFinalInput& input) { + xc_action = EAction::None; + if (x8_subMenu != ESubMenu::ExistingGamePopup) x4_saveUI->ProcessUserInput(input); @@ -957,6 +959,7 @@ void CFrontEndUI::SFusionBonusFrame::Update(float dt, CSaveUI* saveUI) x24_loadedFrame->FindWidget("textpane_proceed")->SetIsVisible(showFusionSuitProceed); std::u16string instructionStr; + x30_textpane_instructions.x0_panes[0]->TextSupport()->SetFontColor(zeus::CColor::skWhite); if (x28_tablegroup_options->GetUserSelection() == 1) { /* Fusion Suit */ @@ -972,12 +975,10 @@ void CFrontEndUI::SFusionBonusFrame::Update(float dt, CSaveUI* saveUI) instructionStr = g_MainStringTable->GetString(79); // You have not completed fusion else if (!g_GameState->SystemOptions().GetPlayerBeatFusion()) instructionStr = g_MainStringTable->GetString(77); // To play NES Metroid - else if (m_nesUnsupported) + else { instructionStr = u"NES Emulator currently unsupported"; - x30_textpane_instructions.x0_panes[0]->TextSupport()->SetText(instructionStr); x30_textpane_instructions.x0_panes[0]->TextSupport()->SetFontColor(zeus::CColor::skYellow); - x30_textpane_instructions.x0_panes[1]->TextSupport()->SetText(instructionStr); } } @@ -1007,7 +1008,6 @@ CFrontEndUI::SFusionBonusFrame::ProcessUserInput(const CFinalInput& input, CSave x39_fusionNotComplete = true; else if (sui) sui->SaveNESState(); - m_nesUnsupported = true; } } } @@ -1032,7 +1032,7 @@ void CFrontEndUI::SFusionBonusFrame::Draw() const void CFrontEndUI::SFusionBonusFrame::DoCancel(CGuiTableGroup* caller) { - if (x39_fusionNotComplete || x3a_mpNotComplete || m_nesUnsupported) + if (x39_fusionNotComplete || x3a_mpNotComplete) { CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } @@ -1094,16 +1094,10 @@ void CFrontEndUI::SFusionBonusFrame::DoAdvance(CGuiTableGroup* caller) x39_fusionNotComplete = false; PlayAdvanceSfx(); } - /* else if (g_GameState->SystemOptions().GetPlayerBeatFusion()) { - x8_action = EAction::PlayNESMetroid; - } - */ - else if (m_nesUnsupported) - { - m_nesUnsupported = false; - PlayAdvanceSfx(); + x8_action = EAction::None; + //x8_action = EAction::PlayNESMetroid; } else { diff --git a/Runtime/MP1/CFrontEndUI.hpp b/Runtime/MP1/CFrontEndUI.hpp index 052d8bbb5..480a3546c 100644 --- a/Runtime/MP1/CFrontEndUI.hpp +++ b/Runtime/MP1/CFrontEndUI.hpp @@ -241,7 +241,6 @@ public: bool x38_lastDoDraw = false; bool x39_fusionNotComplete = false; bool x3a_mpNotComplete = false; - bool m_nesUnsupported = false; SFusionBonusFrame(); void FinishedLoading(); @@ -255,7 +254,6 @@ public: { x39_fusionNotComplete = false; x3a_mpNotComplete = false; - m_nesUnsupported = false; } void DoCancel(CGuiTableGroup* caller); diff --git a/Runtime/MP1/CMemoryCardDriver.cpp b/Runtime/MP1/CMemoryCardDriver.cpp index db20d4b8d..bd733f5f7 100644 --- a/Runtime/MP1/CMemoryCardDriver.cpp +++ b/Runtime/MP1/CMemoryCardDriver.cpp @@ -148,9 +148,9 @@ CMemoryCardDriver::SFileInfo::SFileInfo(kabufuda::ECardSlot port, const std::str : x0_fileInfo(port), x14_name(name) {} CMemoryCardDriver::CMemoryCardDriver(kabufuda::ECardSlot cardPort, ResId saveBanner, - ResId saveIcon0, ResId saveIcon1, bool inGame) + ResId saveIcon0, ResId saveIcon1, bool importPersistent) : x0_cardPort(cardPort), x4_saveBanner(saveBanner), - x8_saveIcon0(saveIcon0), xc_saveIcon1(saveIcon1), x19d_inGame(inGame) + x8_saveIcon0(saveIcon0), xc_saveIcon1(saveIcon1), x19d_importPersistent(importPersistent) { x100_mcFileInfos.reserve(2); x100_mcFileInfos.emplace_back(EFileState::Unknown, SFileInfo(x0_cardPort, SaveFileNames[0])); @@ -205,7 +205,7 @@ void CMemoryCardDriver::ReadFinished() if (header.x4_savePresent[i]) xe4_fileSlots[i] = LoadSaveFile(r); - if (x19d_inGame) + if (x19d_importPersistent) ImportPersistentOptions(); } @@ -412,6 +412,7 @@ void CMemoryCardDriver::StartFileCreate() return; } + x194_fileIdx = 0; x198_fileInfo = std::make_unique(x0_cardPort, SaveFileNames[x194_fileIdx]); InitializeFileInfo(); ECardResult result = x198_fileInfo->CreateFile(); @@ -498,7 +499,6 @@ void CMemoryCardDriver::StartCardFormat() void CMemoryCardDriver::UpdateMountCard(ECardResult result) { - printf("MOUNTCARD\n"); switch (result) { case ECardResult::READY: @@ -508,7 +508,7 @@ void CMemoryCardDriver::UpdateMountCard(ECardResult result) case ECardResult::BROKEN: x10_state = EState::CardMountDone; x14_error = EError::CardBroken; - StartCardCheck(); + //StartCardCheck(); break; default: HandleCardError(result, EState::CardMountFailed); @@ -518,7 +518,6 @@ void CMemoryCardDriver::UpdateMountCard(ECardResult result) void CMemoryCardDriver::UpdateCardProbe() { - printf("PROBECARD\n"); auto result = CMemoryCardSys::CardProbe(x0_cardPort); switch (result.x0_error) { @@ -546,7 +545,6 @@ void CMemoryCardDriver::UpdateCardProbe() void CMemoryCardDriver::UpdateCardCheck(ECardResult result) { - printf("CARDCHECK\n"); switch (result) { case ECardResult::READY: @@ -568,7 +566,6 @@ void CMemoryCardDriver::UpdateCardCheck(ECardResult result) void CMemoryCardDriver::UpdateFileDeleteBad(ECardResult result) { - printf("DELETEBAD\n"); if (result == ECardResult::READY) { x100_mcFileInfos[x194_fileIdx].first = EFileState::NoFile; @@ -591,7 +588,6 @@ void CMemoryCardDriver::UpdateFileDeleteBad(ECardResult result) void CMemoryCardDriver::UpdateFileRead(ECardResult result) { - printf("FILEREAD\n"); if (result == ECardResult::READY) { auto& fileInfo = x100_mcFileInfos[x194_fileIdx]; @@ -636,7 +632,6 @@ void CMemoryCardDriver::UpdateFileRead(ECardResult result) void CMemoryCardDriver::UpdateFileDeleteAlt(ECardResult result) { - printf("DELETEALT\n"); if (result == ECardResult::READY) { x10_state = EState::Ready; @@ -649,7 +644,6 @@ void CMemoryCardDriver::UpdateFileDeleteAlt(ECardResult result) void CMemoryCardDriver::UpdateFileCreate(ECardResult result) { - printf("FILECREATE\n"); if (result == ECardResult::READY) { x10_state = EState::FileCreateDone; @@ -661,7 +655,6 @@ void CMemoryCardDriver::UpdateFileCreate(ECardResult result) void CMemoryCardDriver::UpdateFileWrite(ECardResult result) { - printf("FILEWRITE\n"); if (result == ECardResult::READY) { ECardResult xferResult = x198_fileInfo->PumpCardTransfer(); @@ -669,7 +662,10 @@ void CMemoryCardDriver::UpdateFileWrite(ECardResult result) { x10_state = EState::Ready; if (x198_fileInfo->CloseFile() == ECardResult::READY) + { + CMemoryCardSys::CommitToDisk(x0_cardPort); return; + } NoCardFound(); return; } @@ -689,7 +685,6 @@ void CMemoryCardDriver::UpdateFileWrite(ECardResult result) void CMemoryCardDriver::UpdateFileCreateTransactional(ECardResult result) { - printf("CREATETRANS\n"); if (result == ECardResult::READY) { x10_state = EState::FileCreateTransactionalDone; @@ -701,7 +696,6 @@ void CMemoryCardDriver::UpdateFileCreateTransactional(ECardResult result) void CMemoryCardDriver::UpdateFileWriteTransactional(ECardResult result) { - printf("WRITETRANS\n"); if (result == ECardResult::READY) { ECardResult xferResult = x198_fileInfo->PumpCardTransfer(); @@ -732,7 +726,6 @@ void CMemoryCardDriver::UpdateFileWriteTransactional(ECardResult result) void CMemoryCardDriver::UpdateFileDeleteAltTransactional(ECardResult result) { - printf("DELETEALTTRANS\n"); if (result == ECardResult::READY) { x10_state = EState::FileDeleteAltTransactionalDone; @@ -745,10 +738,10 @@ void CMemoryCardDriver::UpdateFileDeleteAltTransactional(ECardResult result) void CMemoryCardDriver::UpdateFileRenameBtoA(ECardResult result) { - printf("BTOA\n"); if (result == ECardResult::READY) { x10_state = EState::DriverClosed; + CMemoryCardSys::CommitToDisk(x0_cardPort); WriteBackupBuf(); } else @@ -757,7 +750,6 @@ void CMemoryCardDriver::UpdateFileRenameBtoA(ECardResult result) void CMemoryCardDriver::UpdateCardFormat(ECardResult result) { - printf("FORMAT\n"); if (result == ECardResult::READY) x10_state = EState::CardFormatted; else if (result == ECardResult::BROKEN) diff --git a/Runtime/MP1/CMemoryCardDriver.hpp b/Runtime/MP1/CMemoryCardDriver.hpp index fa70e8931..f1e3e3cc7 100644 --- a/Runtime/MP1/CMemoryCardDriver.hpp +++ b/Runtime/MP1/CMemoryCardDriver.hpp @@ -139,11 +139,11 @@ private: u32 x194_fileIdx = -1; std::unique_ptr x198_fileInfo; bool x19c_ = false; - bool x19d_inGame; + bool x19d_importPersistent; public: CMemoryCardDriver(kabufuda::ECardSlot cardPort, ResId saveBanner, - ResId saveIcon0, ResId saveIcon1, bool inGame); + ResId saveIcon0, ResId saveIcon1, bool importPersistent); void NoCardFound(); const CGameState::GameFileStateInfo* GetGameFileStateInfo(int idx); diff --git a/Runtime/MP1/CSaveUI.cpp b/Runtime/MP1/CSaveUI.cpp index 1240295dd..d59e24a01 100644 --- a/Runtime/MP1/CSaveUI.cpp +++ b/Runtime/MP1/CSaveUI.cpp @@ -200,11 +200,18 @@ void CSaveUI::SetUIText() { x91_uiTextDirty = false; - u32 msgA = -1; - u32 msgB = -1; - u32 opt0 = -1; - u32 opt1 = -1; - u32 opt2 = -1; + s32 msgA = -1; + s32 msgB = -1; + s32 opt0 = -1; + s32 opt1 = -1; + s32 opt2 = -1; + + std::u16string msgAStr; + std::u16string msgBStr; + std::u16string opt0Str; + std::u16string opt1Str; + std::u16string opt2Str; + std::u16string opt3Str; switch (x10_uiType) { @@ -218,6 +225,8 @@ void CSaveUI::SetUIText() msgB = 0; // No card found opt0 = 17; // Continue without saving opt1 = 18; // Retry + opt2 = -2; + opt2Str = u"Create Dolphin Card"; break; case EUIType::NeedsFormatBroken: msgB = 1; // Needs format (card broken) @@ -309,30 +318,24 @@ void CSaveUI::SetUIText() default: break; } - std::u16string msgAStr; - if (msgA != -1) + if (msgA > -1) msgAStr = x38_strgMemoryCard->GetString(msgA); - std::u16string msgBStr; - if (msgB != -1) + if (msgB > -1) msgBStr = x38_strgMemoryCard->GetString(msgB); x54_textpane_message->TextSupport()->SetText(msgAStr + msgBStr); - std::u16string opt0Str; - if (opt0 != -1) + if (opt0 > -1) opt0Str = x38_strgMemoryCard->GetString(opt0); x5c_textpane_choice0->TextSupport()->SetText(opt0Str); - std::u16string opt1Str; - if (opt1 != -1) + if (opt1 > -1) opt1Str = x38_strgMemoryCard->GetString(opt1); x60_textpane_choice1->TextSupport()->SetText(opt1Str); - std::u16string opt2Str; - if (opt2 != -1) + if (opt2 > -1) opt2Str = x38_strgMemoryCard->GetString(opt2); x64_textpane_choice2->TextSupport()->SetText(opt2Str); - std::u16string opt3Str; x68_textpane_choice3->TextSupport()->SetText(opt3Str); x5c_textpane_choice0->SetIsSelectable(opt0 != -1); @@ -341,6 +344,7 @@ void CSaveUI::SetUIText() x68_textpane_choice3->SetIsSelectable(false); x58_tablegroup_choices->SetIsActive(opt0 != -1 || opt1 != -1 || opt2 != -1); + x58_tablegroup_choices->SetUserSelection(0); SetUIColors(); } @@ -388,6 +392,13 @@ void CSaveUI::DoAdvance(CGuiTableGroup* caller) ResetCardDriver(); sfx = x84_navConfirmSfx; } + else if (userSel == 2 && x10_uiType == EUIType::NoCardFound) + { + /* Create Dolphin Card */ + CMemoryCardSys::CreateDolphinCard(kabufuda::ECardSlot::SlotA); + ResetCardDriver(); + sfx = x84_navConfirmSfx; + } break; case EUIType::NeedsFormatBroken: @@ -651,7 +662,7 @@ CSaveUI::CSaveUI(ESaveContext saveCtx, u64 serial) x38_strgMemoryCard = g_SimplePool->GetObj("STRG_MemoryCard"); x44_frmeGenericMenu = g_SimplePool->GetObj("FRME_GenericMenu"); - x6c_cardDriver = ConstructCardDriver(bool(x0_saveCtx)); + x6c_cardDriver = ConstructCardDriver(x0_saveCtx == ESaveContext::FrontEnd); if (saveCtx == ESaveContext::InGame) { @@ -669,12 +680,12 @@ CSaveUI::CSaveUI(ESaveContext saveCtx, u64 serial) } } -std::unique_ptr CSaveUI::ConstructCardDriver(bool inGame) +std::unique_ptr CSaveUI::ConstructCardDriver(bool importPersistent) { 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, inGame); + g_ResFactory->GetResourceIdByName("TXTR_SaveIcon1")->id, importPersistent); } } diff --git a/hecl b/hecl index 8915d4941..afe419a5e 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit 8915d494174c221673badcdb25e37fd43d98af88 +Subproject commit afe419a5e923885105a1a26ca21bf87fa7a881c7 diff --git a/kabufuda b/kabufuda index 11d1c676c..537cceca4 160000 --- a/kabufuda +++ b/kabufuda @@ -1 +1 @@ -Subproject commit 11d1c676c4b776561bcfa3960a89c2d0775254fa +Subproject commit 537cceca49bbcc2a71ec9eafd156b5e2496cc31f From 716972cd923973b99128d13e3a1681b0f9ba0ed4 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Fri, 3 Feb 2017 22:20:09 -1000 Subject: [PATCH 2/5] Windows memory card file creation --- Runtime/CMemoryCardSysOSX.cpp | 5 ---- Runtime/CMemoryCardSysWin.cpp | 49 +++++++++++++++++++++++++++++++++++ kabufuda | 2 +- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/Runtime/CMemoryCardSysOSX.cpp b/Runtime/CMemoryCardSysOSX.cpp index f8e80f6c7..b8390fe56 100644 --- a/Runtime/CMemoryCardSysOSX.cpp +++ b/Runtime/CMemoryCardSysOSX.cpp @@ -36,11 +36,6 @@ kabufuda::SystemString CMemoryCardSys::_CreateDolphinCard(kabufuda::ECardSlot sl FILE* fp = hecl::Fopen(path.c_str(), "wb"); if (!fp) return {}; - /* - const u32 fword = 0xffffffff; - for (int i=0 ; i<0x1000000/4 ; ++i) - fwrite(&fword, 1, 4, fp); - */ fclose(fp); return path; diff --git a/Runtime/CMemoryCardSysWin.cpp b/Runtime/CMemoryCardSysWin.cpp index 6e32cb640..9ebdbc216 100644 --- a/Runtime/CMemoryCardSysWin.cpp +++ b/Runtime/CMemoryCardSysWin.cpp @@ -52,4 +52,53 @@ kabufuda::SystemString CMemoryCardSys::ResolveDolphinCardPath(kabufuda::ECardSlo return path; } +kabufuda::SystemString CMemoryCardSys::_CreateDolphinCard(kabufuda::ECardSlot slot) +{ + /* Detect where the User directory is. There are two different cases + * 1. HKCU\Software\Dolphin Emulator\UserConfigPath exists + * -> Use this as the user directory path + * 2. My Documents exists + * -> Use My Documents\Dolphin Emulator as the User directory path + */ + + /* Check our registry keys */ + HKEY hkey; + kabufuda::SystemChar configPath[MAX_PATH] = {0}; + if (RegOpenKeyEx(HKEY_CURRENT_USER, _S("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE, + &hkey) == ERROR_SUCCESS) + { + DWORD size = MAX_PATH; + if (RegQueryValueEx(hkey, _S("UserConfigPath"), nullptr, nullptr, (LPBYTE)configPath, + &size) != ERROR_SUCCESS) + configPath[0] = 0; + RegCloseKey(hkey); + } + + /* Get My Documents path in case we need it. */ + kabufuda::SystemChar my_documents[MAX_PATH]; + bool my_documents_found = SUCCEEDED( + SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, my_documents)); + + kabufuda::SystemString path; + if (configPath[0]) /* Case 1 */ + path = configPath; + else if (my_documents_found) /* Case 2 */ + path = kabufuda::SystemString(my_documents) + _S("/Dolphin Emulator"); + else /* Unable to find */ + return {}; + + path += _S("/GC"); + if (hecl::RecursiveMakeDir(path.c_str()) < 0) + return {}; + + path += hecl::SysFormat(_S("/MemoryCard%c.USA.raw"), + slot == kabufuda::ECardSlot::SlotA ? _S('A') : _S('B')); + FILE* fp = hecl::Fopen(path.c_str(), _S("wb")); + if (!fp) + return {}; + fclose(fp); + + return path; +} + } diff --git a/kabufuda b/kabufuda index 537cceca4..bb972f8f3 160000 --- a/kabufuda +++ b/kabufuda @@ -1 +1 @@ -Subproject commit 537cceca49bbcc2a71ec9eafd156b5e2496cc31f +Subproject commit bb972f8f36cfd6b8b65b3e53352880b039a78393 From b5c6d68ec6e3778864c95b9cae6ceeac8eacb1cf Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sat, 4 Feb 2017 08:29:59 -1000 Subject: [PATCH 3/5] Update hecl --- hecl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hecl b/hecl index afe419a5e..532fd0ede 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit afe419a5e923885105a1a26ca21bf87fa7a881c7 +Subproject commit 532fd0ede4078a0c3cf88868a53932a46f575676 From 5cb2589024f3e7fcd659fc9212fd306a32781d70 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sat, 4 Feb 2017 20:20:31 -1000 Subject: [PATCH 4/5] Update nod --- DataSpec/SpecBase.cpp | 2 +- nod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DataSpec/SpecBase.cpp b/DataSpec/SpecBase.cpp index 18d47290e..bebc2328c 100644 --- a/DataSpec/SpecBase.cpp +++ b/DataSpec/SpecBase.cpp @@ -22,7 +22,7 @@ static const hecl::SystemChar* MomErr[] = _S("HECL is experiencing a PTSD attack"), _S("Unable to freeze metroids"), _S("Ridley ate your homework"), - _S("Expected 0 maternal symbolisms, found ∞"), + _S("Expected 0 maternal symbolisms, found 2147483647"), _S("Contradictive narratives unsupported"), _S("Wiimote profile \"NES + Zapper\" not recognized"), _S("Unable to find Waldo"), diff --git a/nod b/nod index b3a76428d..dc474ad15 160000 --- a/nod +++ b/nod @@ -1 +1 @@ -Subproject commit b3a76428da3bfb83bd973f985b0760a6b55c2abe +Subproject commit dc474ad1560e93f95d99d7577703387a859d7d26 From 1c86d0ac93fd429d505e6abc61db84e401ff6ec1 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sat, 4 Feb 2017 21:00:23 -1000 Subject: [PATCH 5/5] Update nod --- nod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nod b/nod index dc474ad15..e86971c9e 160000 --- a/nod +++ b/nod @@ -1 +1 @@ -Subproject commit dc474ad1560e93f95d99d7577703387a859d7d26 +Subproject commit e86971c9e082b58bb04ee794a106874b3ceae1c7