diff --git a/Runtime/CBasics.hpp b/Runtime/CBasics.hpp index 02007dd8f..91030ea84 100644 --- a/Runtime/CBasics.hpp +++ b/Runtime/CBasics.hpp @@ -12,6 +12,21 @@ namespace urde using OSTime = s64; +struct OSCalendarTime +{ + int x0_sec; // seconds after the minute [0, 61] + int x4_min; // minutes after the hour [0, 59] + int x8_hour; // hours since midnight [0, 23] + int xc_mday; // day of the month [1, 31] + int x10_mon; // month since January [0, 11] + int x14_year; // years in AD [1, ...] + int x18_wday; // days since Sunday [0, 6] + int x1c_yday; // days since January 1 [0, 365] + + int x20_msec; // milliseconds after the second [0,999] + int x24_usec; // microseconds after the millisecond [0,999] +}; + class CBasics { public: @@ -23,6 +38,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); }; } diff --git a/Runtime/CBasicsPC.cpp b/Runtime/CBasicsPC.cpp index c7127df94..ccacdabfe 100644 --- a/Runtime/CBasicsPC.cpp +++ b/Runtime/CBasicsPC.cpp @@ -59,4 +59,11 @@ std::chrono::system_clock::time_point CBasics::FromWiiTime(OSTime wiiTime) return std::chrono::system_clock::from_time_t(time - tzDiff); } +OSCalendarTime CBasics::ToCalendarTime(OSTime time) +{ + OSCalendarTime ret = {}; + /* TODO: Finsh */ + return ret; +} + } diff --git a/Runtime/CGameOptions.cpp b/Runtime/CGameOptions.cpp index 2d7e64612..f43d5725d 100644 --- a/Runtime/CGameOptions.cpp +++ b/Runtime/CGameOptions.cpp @@ -54,6 +54,48 @@ CPersistentOptions::CPersistentOptions(CBitStreamReader& stream) } } +void CPersistentOptions::PutTo(CBitStreamWriter& w) const +{ + for (int b=0 ; b<98 ; ++b) + w.WriteEncoded(x0_[b], 1); + + for (int b=0 ; b<64 ; ++b) + w.WriteEncoded(x68_[b], 1); + + w.WriteEncoded(xc0_, 2); + w.WriteEncoded(xc4_, 2); + w.WriteEncoded(xc8_, 1); + w.WriteEncoded(xcc_logScanCount, 7); + w.WriteEncoded(xd0_24_, 1); + w.WriteEncoded(xd0_25_hasHardMode, 1); + w.WriteEncoded(xd0_26_hardModeBeat, 1); + w.WriteEncoded(xd0_27_, 1); + w.WriteEncoded(xd0_28_hasFusion, 1); + w.WriteEncoded(xd0_29_allItemsCollected, 1); + w.WriteEncoded(xbc_, 2); + + auto& memWorlds = g_MemoryCardSys->GetMemoryWorlds(); + for (const auto& world : memWorlds) + { + TLockedToken saveWorld = + g_SimplePool->GetObj(SObjectTag{FOURCC('SAVW'), world.first}); + + for (TEditorId cineId : saveWorld->GetCinematics()) + w.WriteEncoded(GetCinematicState(world.first, cineId), 1); + } +} + +bool CPersistentOptions::GetCinematicState(ResId mlvlId, TEditorId cineId) const +{ + auto existing = std::find_if(xac_cinematicStates.cbegin(), xac_cinematicStates.cend(), + [&](const std::pair& pair) -> bool + { + return pair.first == mlvlId && pair.second == cineId; + }); + + return existing != xac_cinematicStates.cend(); +} + void CPersistentOptions::SetCinematicState(ResId mlvlId, TEditorId cineId, bool state) { auto existing = std::find_if(xac_cinematicStates.cbegin(), xac_cinematicStates.cend(), diff --git a/Runtime/CGameOptions.hpp b/Runtime/CGameOptions.hpp index 20e665631..d5b145be5 100644 --- a/Runtime/CGameOptions.hpp +++ b/Runtime/CGameOptions.hpp @@ -40,6 +40,7 @@ public: CPersistentOptions() = default; CPersistentOptions(CBitStreamReader& stream); + bool GetCinematicState(ResId mlvlId, TEditorId cineId) const; void SetCinematicState(ResId mlvlId, TEditorId cineId, bool state); bool GetPlayerHasHardMode() const { return xd0_25_hasHardMode; } void SetPlayerHasHardMode(bool v) { xd0_25_hasHardMode = v; } @@ -51,6 +52,7 @@ public: void SetAllItemsCollected(bool v) { xd0_29_allItemsCollected = v; } u32 GetLogScanCount() const { return xcc_logScanCount; } void SetLogScanCount(u32 v) { xcc_logScanCount = v; } + void PutTo(CBitStreamWriter& w) const; }; /** Options tracked per game session */ diff --git a/Runtime/CGameState.cpp b/Runtime/CGameState.cpp index 61e9a194e..16d456635 100644 --- a/Runtime/CGameState.cpp +++ b/Runtime/CGameState.cpp @@ -183,7 +183,7 @@ CGameState::CGameState(CBitStreamReader& stream) } } -void CGameState::MergePersistentOptions(const CPersistentOptions& opts) +void CGameState::ImportPersistentOptions(const CPersistentOptions& opts) { if (opts.xd0_24_) xa8_systemOptions.xd0_24_ = true; @@ -197,6 +197,24 @@ void CGameState::MergePersistentOptions(const CPersistentOptions& opts) xa8_systemOptions.SetPlayerBeatHardMode(opts.GetPlayerBeatHardMode()); } +void CGameState::ExportPersistentOptions(CPersistentOptions& opts) const +{ + if (xa8_systemOptions.xd0_24_) + opts.xd0_24_ = true; + if (xa8_systemOptions.xd0_27_) + opts.xd0_27_ = true; + if (&opts != &xa8_systemOptions) + memcpy(opts.x0_, xa8_systemOptions.x0_, 98); + opts.SetPlayerHasFusion(xa8_systemOptions.GetPlayerHasFusion()); +} + +void CGameState::WriteBackupBuf() +{ + x218_backupBuf.resize(940); + CBitStreamWriter w(x218_backupBuf.data(), 940); + PutTo(w); +} + void CGameState::PutTo(CBitStreamWriter& writer) const { for (u32 i = 0; i < 128; i++) diff --git a/Runtime/CGameState.hpp b/Runtime/CGameState.hpp index eef71b7e1..eeb83ddac 100644 --- a/Runtime/CGameState.hpp +++ b/Runtime/CGameState.hpp @@ -80,8 +80,8 @@ class CGameState CPersistentOptions xa8_systemOptions; CGameOptions x17c_gameOptions; CHintOptions x1f8_hintOptions; - u32 x210_; - u32 x214_; + u64 x210_cardSerial; + std::vector x218_backupBuf; union { @@ -108,7 +108,10 @@ public: CWorldState& CurrentWorldState() { return StateForWorld(x84_mlvlId); } ResId CurrentWorldAssetId() const { return x84_mlvlId; } void SetHardMode(bool v) { x228_24_hardMode = v; } - void MergePersistentOptions(const CPersistentOptions& opts); + void ImportPersistentOptions(const CPersistentOptions& opts); + void ExportPersistentOptions(CPersistentOptions& opts) const; + void WriteBackupBuf(); + void SetCardSerial(u64 serial) { x210_cardSerial = serial; } void PutTo(CBitStreamWriter& writer) const; struct GameFileStateInfo diff --git a/Runtime/CMemoryCardSys.cpp b/Runtime/CMemoryCardSys.cpp index 33f5f7b81..9c6dcbab2 100644 --- a/Runtime/CMemoryCardSys.cpp +++ b/Runtime/CMemoryCardSys.cpp @@ -3,6 +3,8 @@ #include "CSimplePool.hpp" #include "CGameState.hpp" #include "GuiSys/CStringTable.hpp" +#include "CCRC32.hpp" +#include "Graphics/CTexture.hpp" namespace urde { @@ -132,6 +134,199 @@ bool CMemoryCardSys::InitializePump() return false; } +void CMemoryCardSys::CCardFileInfo::LockBannerToken(ResId bannerTxtr, CSimplePool& sp) +{ + x3c_bannerTex = bannerTxtr; + x40_bannerTok.emplace(sp.GetObj({FOURCC('TXTR'), bannerTxtr}, m_texParam)); +} + +CMemoryCardSys::CCardFileInfo::Icon::Icon(ResId id, u32 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) +{ + x50_iconToks.emplace_back(iconTxtr, speed, sp, m_texParam); +} + +u32 CMemoryCardSys::CCardFileInfo::CalculateBannerDataSize() const +{ + u32 ret = 68; + if (x3c_bannerTex != -1) + { + if ((*x40_bannerTok)->GetMemoryCardTexelFormat() == ETexelFormat::RGB5A3) + ret = 6212; + else + ret = 3652; + } + + bool paletteTex = false; + for (const Icon& icon : x50_iconToks) + { + if (icon.x8_tex->GetMemoryCardTexelFormat() == ETexelFormat::RGB5A3) + ret += 2048; + else + { + ret += 1024; + paletteTex = true; + } + } + + if (paletteTex) + ret += 512; + + return ret; +} + +u32 CMemoryCardSys::CCardFileInfo::CalculateTotalDataSize() const +{ + return (CalculateBannerDataSize() + xf4_saveBuffer.size() + 8191) & ~8191; +} + +void CMemoryCardSys::CCardFileInfo::BuildCardBuffer() +{ + u32 bannerSz = CalculateBannerDataSize(); + x104_cardBuffer.resize((bannerSz + xf4_saveBuffer.size() + 8191) & ~8191); + + CMemoryOutStream w(x104_cardBuffer.data(), x104_cardBuffer.size()); + w.writeUint32Big(0); + char name[64]; + strncpy(name, x28_name2.data(), 64); + w.writeBytes(name, 64); + WriteBannerData(w); + WriteIconData(w); + memmove(x104_cardBuffer.data() + bannerSz, xf4_saveBuffer.data(), xf4_saveBuffer.size()); + reinterpret_cast(*x104_cardBuffer.data()) = + hecl::SBig(CCRC32::Calculate(x104_cardBuffer.data() + 4, x104_cardBuffer.size() - 4)); + + xf4_saveBuffer.clear(); +} + +void CMemoryCardSys::CCardFileInfo::WriteBannerData(CMemoryOutStream& out) const +{ + if (x3c_bannerTex != -1) + { + const TLockedToken& tex = *x40_bannerTok; + u32 bufSz; + ETexelFormat fmt; + std::unique_ptr palette; + std::unique_ptr texels = tex->BuildMemoryCardTex(bufSz, fmt, palette); + + if (fmt == ETexelFormat::RGB5A3) + out.writeBytes(texels.get(), 6144); + else + out.writeBytes(texels.get(), 3072); + + if (fmt == ETexelFormat::C8) + out.writeBytes(palette.get(), 512); + } +} + +void CMemoryCardSys::CCardFileInfo::WriteIconData(CMemoryOutStream& out) const +{ + std::unique_ptr palette; + for (const Icon& icon : x50_iconToks) + { + u32 bufSz; + ETexelFormat fmt; + std::unique_ptr texels = icon.x8_tex->BuildMemoryCardTex(bufSz, fmt, palette); + + if (fmt == ETexelFormat::RGB5A3) + out.writeBytes(texels.get(), 2048); + else + out.writeBytes(texels.get(), 1024); + } + if (palette) + out.writeBytes(palette.get(), 512); +} + +CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::PumpCardTransfer() +{ + if (x0_status == EStatus::Standby) + return ECardResult::CARD_RESULT_READY; + else if (x0_status == EStatus::Transferring) + { + ECardResult result = CMemoryCardSys::GetResultCode(GetCardPort()); + if (result != ECardResult::CARD_RESULT_BUSY) + x104_cardBuffer.clear(); + if (result != ECardResult::CARD_RESULT_READY) + return result; + x0_status = EStatus::Done; + CARDStat stat = {}; + result = GetStatus(stat); + if (result != ECardResult::CARD_RESULT_READY) + return result; + result = CMemoryCardSys::SetStatus(GetCardPort(), GetFileNo(), stat); + if (result != ECardResult::CARD_RESULT_READY) + return result; + return ECardResult::CARD_RESULT_BUSY; + } + else + { + ECardResult result = CMemoryCardSys::GetResultCode(GetCardPort()); + if (result == ECardResult::CARD_RESULT_READY) + x0_status = EStatus::Standby; + return result; + } +} + +CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::GetStatus(CARDStat& stat) const +{ + ECardResult result = CMemoryCardSys::GetStatus(GetCardPort(), GetFileNo(), stat); + if (result != ECardResult::CARD_RESULT_READY) + return result; + + stat.SetCommentAddr(4); + stat.SetIconAddr(68); + + u32 bannerFmt; + if (x3c_bannerTex != -1) + { + if ((*x40_bannerTok)->GetMemoryCardTexelFormat() == ETexelFormat::RGB5A3) + bannerFmt = 2; + else + bannerFmt = 1; + } + else + bannerFmt = 0; + stat.SetBannerFormat(bannerFmt); + + int idx = 0; + for (const Icon& icon : x50_iconToks) + { + stat.SetIconFormat(icon.x8_tex->GetMemoryCardTexelFormat() == ETexelFormat::RGB5A3 ? 2 : 1, idx); + stat.SetIconSpeed(icon.x4_speed, idx); + ++idx; + } + if (idx < 8) + { + stat.SetIconFormat(0, idx); + stat.SetIconSpeed(0, idx); + } + + return ECardResult::CARD_RESULT_READY; +} + +CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::CreateFile() +{ + return ECardResult::CARD_RESULT_READY; +} + +CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::Write() +{ + BuildCardBuffer(); + //DCStoreRange(info.x104_cardBuffer.data(), info.x104_cardBuffer.size()); + //CARDWriteAsync(&info.x4_info, info.x104_cardBuffer.data(), info.x104_cardBuffer.size(), 0, 0); + return ECardResult::CARD_RESULT_READY; +} + +CMemoryCardSys::ECardResult CMemoryCardSys::CCardFileInfo::Close() +{ + EMemoryCardPort port = GetCardPort(); + //CARDClose(port); + x4_info.chan = port; + return ECardResult::CARD_RESULT_READY; +} + CMemoryCardSys::CardProbeResults CMemoryCardSys::CardProbe(EMemoryCardPort port) { return {}; @@ -167,6 +362,11 @@ CMemoryCardSys::ECardResult CMemoryCardSys::GetStatus(EMemoryCardPort port, int return ECardResult::CARD_RESULT_READY; } +CMemoryCardSys::ECardResult CMemoryCardSys::SetStatus(EMemoryCardPort port, int fileNo, const CARDStat& stat) +{ + return ECardResult::CARD_RESULT_READY; +} + CMemoryCardSys::ECardResult CMemoryCardSys::DeleteFile(EMemoryCardPort port, const char* name) { return ECardResult::CARD_RESULT_READY; @@ -177,4 +377,14 @@ CMemoryCardSys::ECardResult CMemoryCardSys::FastDeleteFile(EMemoryCardPort port, return ECardResult::CARD_RESULT_READY; } +CMemoryCardSys::ECardResult CMemoryCardSys::Rename(EMemoryCardPort port, const char* oldName, const char* newName) +{ + return ECardResult::CARD_RESULT_READY; +} + +CMemoryCardSys::ECardResult CMemoryCardSys::FormatCard(EMemoryCardPort port) +{ + return ECardResult::CARD_RESULT_READY; +} + } diff --git a/Runtime/CMemoryCardSys.hpp b/Runtime/CMemoryCardSys.hpp index 3734504b6..0b661eea8 100644 --- a/Runtime/CMemoryCardSys.hpp +++ b/Runtime/CMemoryCardSys.hpp @@ -16,6 +16,7 @@ namespace urde { class CDummyWorld; class CStringTable; +class CSimplePool; class CSaveWorldMemory { @@ -79,6 +80,7 @@ public: CARD_RESULT_ENCODING = -13, CARD_RESULT_BROKEN = -6, CARD_RESULT_IOERROR = -5, + CARD_RESULT_NOFILE = -4, CARD_RESULT_NOCARD = -3, CARD_RESULT_WRONGDEVICE = -2, CARD_RESULT_BUSY = -1, @@ -116,6 +118,7 @@ public: 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; } @@ -136,6 +139,68 @@ public: 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; + TLockedToken x8_tex; + Icon(ResId id, u32 speed, CSimplePool& sp, const CVParamTransfer& cv); + }; + + enum class EStatus + { + Standby, + Transferring, + Done + }; + + EStatus x0_status = EStatus::Standby; + CARDFileInfo x4_info; + std::string x18_name; + std::string x28_name2; + ResId x3c_bannerTex = -1; + std::experimental::optional> x40_bannerTok; + rstl::reserved_vector x50_iconToks; + std::vector xf4_saveBuffer; + std::vector x104_cardBuffer; + + CVParamTransfer m_texParam = {new TObjOwnerParam(SBIG('OTEX'))}; + + CCardFileInfo(EMemoryCardPort port, const std::string& name) + : x4_info(port), x18_name(name) {} + + void LockBannerToken(ResId bannerTxtr, CSimplePool& sp); + void LockIconToken(ResId iconTxtr, u32 speed, CSimplePool& sp); + + EMemoryCardPort GetCardPort() const { return x4_info.chan; } + int GetFileNo() const { return x4_info.fileNo; } + u32 CalculateBannerDataSize() const; + u32 CalculateTotalDataSize() const; + void BuildCardBuffer(); + void WriteBannerData(CMemoryOutStream& out) const; + void WriteIconData(CMemoryOutStream& out) const; + ECardResult PumpCardTransfer(); + ECardResult GetStatus(CARDStat& stat) const; + ECardResult CreateFile(); + ECardResult Write(); + ECardResult Close(); + }; + static CardProbeResults CardProbe(EMemoryCardPort port); static ECardResult MountCard(EMemoryCardPort port); static ECardResult CheckCard(EMemoryCardPort port); @@ -143,8 +208,11 @@ public: 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); }; } diff --git a/Runtime/Character/CAllFormatsAnimSource.cpp b/Runtime/Character/CAllFormatsAnimSource.cpp index 724355c95..a33fb580a 100644 --- a/Runtime/Character/CAllFormatsAnimSource.cpp +++ b/Runtime/Character/CAllFormatsAnimSource.cpp @@ -72,9 +72,7 @@ CFactoryFnReturn AnimSourceFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& params, CObjectReference* selfRef) { - CSimplePool* sp = static_cast( - static_cast*>( - params.GetObj())->GetParam()); + CSimplePool* sp = params.GetOwnedObj(); return TToken::GetIObjObjectFor( std::make_unique(in, *sp, tag)); } diff --git a/Runtime/Character/CCharacterFactory.cpp b/Runtime/Character/CCharacterFactory.cpp index a0b8f11d7..186b53629 100644 --- a/Runtime/Character/CCharacterFactory.cpp +++ b/Runtime/Character/CCharacterFactory.cpp @@ -22,8 +22,7 @@ CFactoryFnReturn CCharacterFactory::CDummyFactory::Build(const SObjectTag& tag, CObjectReference* selfRef) { - const CCharacterInfo& charInfo = - *static_cast&>(*params.GetObj()).GetParam(); + const CCharacterInfo& charInfo = *params.GetOwnedObj(); switch (tag.type.toUint32() & 0x1) { diff --git a/Runtime/Collision/CCollisionResponseData.cpp b/Runtime/Collision/CCollisionResponseData.cpp index 6390b979b..a5ae57af3 100644 --- a/Runtime/Collision/CCollisionResponseData.cpp +++ b/Runtime/Collision/CCollisionResponseData.cpp @@ -284,7 +284,7 @@ FourCC CCollisionResponseData::UncookedResType() CFactoryFnReturn FCollisionResponseDataFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms) { - CSimplePool* sp = static_cast(static_cast*>(vparms.GetObj())->GetParam()); + CSimplePool* sp = vparms.GetOwnedObj(); return TToken::GetIObjObjectFor(std::unique_ptr(new CCollisionResponseData(in, sp))); } diff --git a/Runtime/Graphics/CModelBoo.cpp b/Runtime/Graphics/CModelBoo.cpp index 895fd403f..bf6235a0a 100644 --- a/Runtime/Graphics/CModelBoo.cpp +++ b/Runtime/Graphics/CModelBoo.cpp @@ -9,6 +9,7 @@ #include "Graphics/CBooRenderer.hpp" #include "Character/CSkinRules.hpp" #include "GameGlobalObjects.hpp" +#include "CSimplePool.hpp" #include namespace urde @@ -807,8 +808,8 @@ CFactoryFnReturn FModelFactory(const urde::SObjectTag& tag, const urde::CVParamTransfer& vparms, CObjectReference* selfRef) { - IObjectStore* store = static_cast*>(vparms.GetObj())->GetParam(); - CFactoryFnReturn ret = TToken::GetIObjObjectFor(std::make_unique(std::move(in), len, store, selfRef)); + CSimplePool* sp = vparms.GetOwnedObj(); + CFactoryFnReturn ret = TToken::GetIObjObjectFor(std::make_unique(std::move(in), len, sp, selfRef)); return ret; } diff --git a/Runtime/Graphics/CTexture.hpp b/Runtime/Graphics/CTexture.hpp index 5c916a249..39b3cce1d 100644 --- a/Runtime/Graphics/CTexture.hpp +++ b/Runtime/Graphics/CTexture.hpp @@ -21,6 +21,7 @@ class CTexture boo::GraphicsDataToken m_booToken; boo::ITexture* m_booTex; boo::ITexture* m_paletteTex; + std::unique_ptr m_otex; size_t ComputeMippedTexelCount(); size_t ComputeMippedBlockCountDXT1(); @@ -39,18 +40,22 @@ class CTexture void BuildC8(const void* data, size_t length); public: - CTexture(std::unique_ptr&& in, u32 length); + CTexture(std::unique_ptr&& in, u32 length, bool otex); enum class EClampMode { None, One }; ETexelFormat GetTexelFormat() const {return x0_fmt;} + ETexelFormat GetMemoryCardTexelFormat() const + {return x0_fmt == ETexelFormat::C8PC ? ETexelFormat::C8 : ETexelFormat::RGB5A3;} u16 GetWidth() const {return x4_w;} u16 GetHeight() const {return x6_h;} void Load(int slot, EClampMode clamp) const; boo::ITexture* GetBooTexture() {return m_booTex;} boo::ITexture* GetPaletteTexture() {return m_paletteTex;} + std::unique_ptr BuildMemoryCardTex(u32& sizeOut, ETexelFormat& fmtOut, + std::unique_ptr& paletteOut) const; }; CFactoryFnReturn FTextureFactory(const urde::SObjectTag& tag, diff --git a/Runtime/Graphics/CTextureBoo.cpp b/Runtime/Graphics/CTextureBoo.cpp index 2bbc63966..229a0a999 100644 --- a/Runtime/Graphics/CTextureBoo.cpp +++ b/Runtime/Graphics/CTextureBoo.cpp @@ -684,7 +684,7 @@ void CTexture::BuildC8(const void* data, size_t length) }); } -CTexture::CTexture(std::unique_ptr&& in, u32 length) +CTexture::CTexture(std::unique_ptr&& in, u32 length, bool otex) { std::unique_ptr owned = std::move(in); athena::io::MemoryReader r(owned.get(), length); @@ -737,6 +737,9 @@ CTexture::CTexture(std::unique_ptr&& in, u32 length) default: Log.report(logvisor::Fatal, "invalid texture type %d for boo", int(x0_fmt)); } + + if (otex) + m_otex = std::move(owned); } void CTexture::Load(int slot, EClampMode clamp) const @@ -744,12 +747,125 @@ void CTexture::Load(int slot, EClampMode clamp) const } +std::unique_ptr CTexture::BuildMemoryCardTex(u32& sizeOut, ETexelFormat& fmtOut, + std::unique_ptr& paletteOut) const +{ + if (!m_otex) + Log.report(logvisor::Fatal, "MemoryCard TXTR not loaded with 'otex'"); + + size_t texelCount = x4_w * x6_h; + std::unique_ptr ret; + if (x0_fmt == ETexelFormat::RGBA8PC) + { + sizeOut = texelCount * 2; + fmtOut = ETexelFormat::RGB5A3; + ret.reset(new u8[sizeOut]); + u16* texel = reinterpret_cast(ret.get()); + + int w = x4_w; + int h = x6_h; + const RGBA8* sourceMip = reinterpret_cast(m_otex.get() + 12); + int bwidth = (w + 3) / 4; + int bheight = (h + 3) / 4; + for (int by=0 ; by> 3 << 10) | + (source[x].g >> 3 << 5) | + (source[x].b >> 3))); + } + else + { + *texel++ = hecl::SBig(u16((source[x].r >> 4 << 8) | + (source[x].g >> 4 << 4) | + (source[x].b >> 4) | + (source[x].a >> 5 << 12))); + } + } + } + } + } + } + else if (x0_fmt == ETexelFormat::C8PC) + { + sizeOut = texelCount; + fmtOut = ETexelFormat::C8; + ret.reset(new u8[sizeOut]); + paletteOut.reset(new u8[512]); + u8* texel = ret.get(); + u16* paletteColors = reinterpret_cast(paletteOut.get()); + + int w = x4_w; + int h = x6_h; + const u8* data = m_otex.get() + 12; + u32 nentries = hecl::SBig(*reinterpret_cast(data)); + const RGBA8* paletteTexels = reinterpret_cast(data + 4); + const u8* sourceMip = data + 4 + nentries * 4; + + for (int i=0; i<256; ++i) + { + u16& color = paletteColors[i]; + if (i < nentries) + color = 0; + else + { + const RGBA8& colorIn = paletteTexels[i]; + if (colorIn.a == 0xff) + { + color = hecl::SBig(u16((colorIn.r >> 3 << 10) | + (colorIn.g >> 3 << 5) | + (colorIn.b >> 3))); + } + else + { + color = hecl::SBig(u16((colorIn.r >> 4 << 8) | + (colorIn.g >> 4 << 4) | + (colorIn.b >> 4) | + (colorIn.a >> 5 << 12))); + } + } + } + + int bwidth = (w + 7) / 8; + int bheight = (h + 3) / 4; + for (int by=0 ; by&& in, u32 len, const urde::CVParamTransfer& vparms, CObjectReference* selfRef) { - return TToken::GetIObjObjectFor(std::make_unique(std::move(in), len)); + return TToken::GetIObjObjectFor(std::make_unique(std::move(in), len, + vparms.GetOwnedObj() == SBIG('OTEX'))); } } diff --git a/Runtime/GuiSys/CGuiFrame.cpp b/Runtime/GuiSys/CGuiFrame.cpp index 906b6368f..23e3de37a 100644 --- a/Runtime/GuiSys/CGuiFrame.cpp +++ b/Runtime/GuiSys/CGuiFrame.cpp @@ -184,7 +184,7 @@ std::unique_ptr RGuiFrameFactoryInGame(const SObjectTag& tag, CInputStream const CVParamTransfer& cvParms, CObjectReference* selfRef) { - CSimplePool* sp = static_cast(static_cast*>(cvParms.GetObj())->GetParam()); + CSimplePool* sp = cvParms.GetOwnedObj(); std::unique_ptr frame(CGuiFrame::CreateFrame(tag.id, *g_GuiSys, in, sp)); return TToken::GetIObjObjectFor(std::move(frame)); } diff --git a/Runtime/GuiSys/CRasterFont.cpp b/Runtime/GuiSys/CRasterFont.cpp index e64c5590e..1fc4fde15 100644 --- a/Runtime/GuiSys/CRasterFont.cpp +++ b/Runtime/GuiSys/CRasterFont.cpp @@ -2,6 +2,7 @@ #include "CDrawStringOptions.hpp" #include "CTextRenderBuffer.hpp" #include "Graphics/CTexture.hpp" +#include "CSimplePool.hpp" namespace urde { @@ -195,8 +196,8 @@ void CRasterFont::GetSize(const CDrawStringOptions& opts, int& width, int& heigh std::unique_ptr FRasterFontFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms, CObjectReference* selfRef) { - return TToken::GetIObjObjectFor( - std::make_unique(in, *static_cast*>(vparms.GetObj())->GetParam())); + CSimplePool* sp = vparms.GetOwnedObj(); + return TToken::GetIObjObjectFor(std::make_unique(in, *sp)); } } diff --git a/Runtime/IVParamObj.hpp b/Runtime/IVParamObj.hpp index b51a2ef17..f0246b2b0 100644 --- a/Runtime/IVParamObj.hpp +++ b/Runtime/IVParamObj.hpp @@ -13,6 +13,15 @@ public: virtual ~IVParamObj() {} }; +template +class TObjOwnerParam : public IVParamObj +{ + T m_param; +public: + TObjOwnerParam(T&& obj) : m_param(std::move(obj)) {} + T& GetParam() {return m_param;} +}; + class CVParamTransfer { std::shared_ptr m_ref; @@ -23,16 +32,10 @@ public: IVParamObj* GetObj() const {return m_ref.get();} CVParamTransfer ShareTransferRef() {return CVParamTransfer(*this);} - static CVParamTransfer Null() {return CVParamTransfer();} -}; + template + T& GetOwnedObj() const {return static_cast*>(GetObj())->GetParam();} -template -class TObjOwnerParam : public IVParamObj -{ - T m_param; -public: - TObjOwnerParam(T&& obj) : m_param(std::move(obj)) {} - T& GetParam() {return m_param;} + static CVParamTransfer Null() {return CVParamTransfer();} }; } diff --git a/Runtime/MP1/CMemoryCardDriver.cpp b/Runtime/MP1/CMemoryCardDriver.cpp index 880f40432..a6c77708a 100644 --- a/Runtime/MP1/CMemoryCardDriver.cpp +++ b/Runtime/MP1/CMemoryCardDriver.cpp @@ -7,9 +7,21 @@ namespace urde namespace MP1 { +static const char* SaveFileNames[] = +{ + "MetroidPrime A", + "MetroidPrime B" +}; + using ECardResult = CMemoryCardSys::ECardResult; using EMemoryCardPort = CMemoryCardSys::EMemoryCardPort; +ECardResult CMemoryCardDriver::SFileInfo::Open() +{ + //CARDOpen(GetFileCardPort(), x14_name.data(), &x0_fileInfo); + return ECardResult::CARD_RESULT_READY; +} + ECardResult CMemoryCardDriver::SFileInfo::Close() { auto backup = GetFileCardPort(); @@ -19,6 +31,20 @@ ECardResult CMemoryCardDriver::SFileInfo::Close() return result; } +CMemoryCardSys::ECardResult CMemoryCardDriver::SFileInfo::StartRead() +{ + CMemoryCardSys::CARDStat stat = {}; + ECardResult result = CMemoryCardSys::GetStatus(GetFileCardPort(), GetFileNo(), stat); + if (result != ECardResult::CARD_RESULT_READY) + return result; + + u32 length = stat.GetFileLength(); + x34_saveData.clear(); + x24_saveFileData.resize(length); + //return CARDReadAsync(&x0_fileInfo, x24_saveFileData.data(), length, 0, 0); + return ECardResult::CARD_RESULT_READY; +} + ECardResult CMemoryCardDriver::SFileInfo::TryFileRead() { ECardResult res = CMemoryCardSys::GetResultCode(GetFileCardPort()); @@ -124,13 +150,13 @@ CMemoryCardDriver::SFileInfo::SFileInfo(EMemoryCardPort port, } CMemoryCardDriver::CMemoryCardDriver(EMemoryCardPort cardPort, ResId saveBanner, - ResId saveIcon0, ResId saveIcon1, bool mergePersistent) + ResId saveIcon0, ResId saveIcon1, bool importPersistent) : x0_cardPort(cardPort), x4_saveBanner(saveBanner), - x8_saveIcon0(saveIcon0), xc_saveIcon1(saveIcon1), x19d_doMergePersistent(mergePersistent) + x8_saveIcon0(saveIcon0), xc_saveIcon1(saveIcon1), x19d_doImportPersistent(importPersistent) { x100_mcFileInfos.reserve(2); - x100_mcFileInfos.emplace_back(0, SFileInfo(x0_cardPort, "MetroidPrime A")); - x100_mcFileInfos.emplace_back(0, SFileInfo(x0_cardPort, "MetroidPrime B")); + x100_mcFileInfos.emplace_back(0, SFileInfo(x0_cardPort, SaveFileNames[0])); + x100_mcFileInfos.emplace_back(0, SFileInfo(x0_cardPort, SaveFileNames[1])); } void CMemoryCardDriver::FinishedLoading() @@ -152,7 +178,7 @@ void CMemoryCardDriver::FinishedLoading2() x14_error = EError::Seven; return; } - x10_state = EState::Five; + x10_state = EState::CardNeedsMount; MountCard(); break; case ECardResult::CARD_RESULT_BUSY: @@ -169,13 +195,13 @@ void CMemoryCardDriver::FinishedLoading2() void CMemoryCardDriver::NoCardFound() { - x10_state = EState::Two; + x10_state = EState::NoCard; static_cast(g_Main)->SetCardInserted(false); } void CMemoryCardDriver::MountCard() { - x10_state = EState::TwentySix; + x10_state = EState::CardMount; x14_error = EError::Zero; ECardResult result = CMemoryCardSys::MountCard(x0_cardPort); if (result != ECardResult::CARD_RESULT_READY) @@ -229,22 +255,31 @@ void CMemoryCardDriver::ReadFinished() for (int i=0 ; i<3 ; ++i) xe4_fileSlots[i] = LoadSaveFile(r); - if (x19d_doMergePersistent) - MergePersistentOptions(); + if (x19d_doImportPersistent) + ImportPersistentOptions(); } -void CMemoryCardDriver::MergePersistentOptions() +void CMemoryCardDriver::ImportPersistentOptions() { CBitStreamReader r(x30_systemData, 174); CPersistentOptions opts(r); - g_GameState->MergePersistentOptions(opts); + g_GameState->ImportPersistentOptions(opts); +} + +void CMemoryCardDriver::ExportPersistentOptions() +{ + CBitStreamReader r(x30_systemData, 174); + CPersistentOptions opts(r); + g_GameState->ExportPersistentOptions(opts); + CBitStreamWriter w(x30_systemData, 174); + opts.PutTo(w); } void CMemoryCardDriver::DeleteFile() { x14_error = EError::Zero; x10_state = EState::Thirty; - SFileInfo& fileInfo = x100_mcFileInfos[bool(x194_fileIdx)].second; + SFileInfo& fileInfo = x100_mcFileInfos[!bool(x194_fileIdx)].second; ECardResult result = CMemoryCardSys::FastDeleteFile(x0_cardPort, fileInfo.GetFileNo()); if (result != ECardResult::CARD_RESULT_READY) Case30(result); @@ -261,11 +296,11 @@ void CMemoryCardDriver::Case26(ECardResult result) switch (result) { case ECardResult::CARD_RESULT_READY: - x10_state = EState::Six; + x10_state = EState::CardMountDone; CheckCard(); break; case ECardResult::CARD_RESULT_BROKEN: - x10_state = EState::Six; + x10_state = EState::CardMountDone; x14_error = EError::One; CheckCard(); break; @@ -280,7 +315,7 @@ void CMemoryCardDriver::Case27(ECardResult result) switch (result) { case ECardResult::CARD_RESULT_READY: - x10_state = EState::Seven; + x10_state = EState::SelectCardFile; if (!GetCardFreeBytes()) return; if (CMemoryCardSys::GetSerialNo(x0_cardPort, x28_cardSerial) == ECardResult::CARD_RESULT_READY) @@ -301,14 +336,14 @@ void CMemoryCardDriver::Case28(ECardResult result) if (result == ECardResult::CARD_RESULT_READY) { x100_mcFileInfos[x194_fileIdx].first = 1; - if (x100_mcFileInfos[bool(x194_fileIdx)].first == 3) + if (x100_mcFileInfos[!bool(x194_fileIdx)].first == 3) { x10_state = EState::Seventeen; GoTo28(); } else { - x10_state = EState::Seven; + x10_state = EState::SelectCardFile; if (!GetCardFreeBytes()) return; GoTo17(); @@ -330,10 +365,10 @@ void CMemoryCardDriver::Case29(ECardResult result) return; } - u32 fileIdx = bool(x194_fileIdx); + u32 fileIdx = !bool(x194_fileIdx); if (readRes == ECardResult::CARD_RESULT_READY) { - x10_state = EState::One; + x10_state = EState::Ready; ReadFinished(); u32 fileId = x100_mcFileInfos[fileIdx].first; if (fileId == 1) @@ -348,7 +383,7 @@ void CMemoryCardDriver::Case29(ECardResult result) x100_mcFileInfos[x194_fileIdx].first = 3; if (x100_mcFileInfos[fileIdx].first == 2) { - x10_state = EState::Seven; + x10_state = EState::SelectCardFile; GoTo17(); } else @@ -364,52 +399,347 @@ void CMemoryCardDriver::Case29(ECardResult result) void CMemoryCardDriver::Case30(ECardResult result) { - + if (result == ECardResult::CARD_RESULT_READY) + { + x10_state = EState::Ready; + if (GetCardFreeBytes()) + CheckCardCapacity(); + } + else + HandleCardError(result, EState::Sixteen); } void CMemoryCardDriver::Case31(ECardResult result) { - + if (result == ECardResult::CARD_RESULT_READY) + { + x10_state = EState::WillWrite; + GoTo32(); + } + else + HandleCardError(result, EState::Eighteen); } void CMemoryCardDriver::Case32(ECardResult result) { - + if (result == ECardResult::CARD_RESULT_READY) + { + ECardResult xferResult = x198_fileInfo->PumpCardTransfer(); + if (xferResult == ECardResult::CARD_RESULT_READY) + { + x10_state = EState::Ready; + if (x198_fileInfo->Close() == ECardResult::CARD_RESULT_READY) + return; + NoCardFound(); + return; + } + if (xferResult == ECardResult::CARD_RESULT_BUSY) + return; + if (xferResult == ECardResult::CARD_RESULT_IOERROR) + { + x10_state = EState::Nineteen; + x14_error = EError::Three; + return; + } + NoCardFound(); + } + else + HandleCardError(result, EState::Nineteen); } void CMemoryCardDriver::Case33(ECardResult result) { - + if (result == ECardResult::CARD_RESULT_READY) + { + x10_state = EState::Nine; + GoTo34(); + } + else + HandleCardError(result, EState::Twenty); } void CMemoryCardDriver::Case34(ECardResult result) { - + if (result == ECardResult::CARD_RESULT_READY) + { + ECardResult xferResult = x198_fileInfo->PumpCardTransfer(); + if (xferResult == ECardResult::CARD_RESULT_READY) + { + x10_state = EState::Ten; + if (x198_fileInfo->Close() != ECardResult::CARD_RESULT_READY) + { + NoCardFound(); + return; + } + GoTo35(); + return; + } + if (xferResult == ECardResult::CARD_RESULT_BUSY) + return; + if (xferResult == ECardResult::CARD_RESULT_IOERROR) + { + x10_state = EState::TwentyOne; + x14_error = EError::Three; + return; + } + NoCardFound(); + } + else + HandleCardError(result, EState::TwentyOne); } void CMemoryCardDriver::Case35(ECardResult result) { - + if (result == ECardResult::CARD_RESULT_READY) + { + x10_state = EState::Eleven; + if (GetCardFreeBytes()) + GoTo36(); + } + else + HandleCardError(result, EState::TwentyTwo); } void CMemoryCardDriver::Case36(ECardResult result) { - + if (result == ECardResult::CARD_RESULT_READY) + { + x10_state = EState::RuntimeBackup; + WriteBackupBuf(); + } + else + HandleCardError(result, EState::TwentyThree); } void CMemoryCardDriver::Case37(ECardResult result) { - + if (result == ECardResult::CARD_RESULT_READY) + x10_state = EState::CardFormatted; + else if (result == ECardResult::CARD_RESULT_BROKEN) + { + x10_state = EState::CardFormatBroken; + x14_error = EError::Three; + } + else + HandleCardError(result, EState::CardFormatBroken); } void CMemoryCardDriver::GoTo17() { + x14_error = EError::Zero; + for (std::pair& info : x100_mcFileInfos) + { + if (info.first == 0) + { + ECardResult result = info.second.Open(); + if (result == ECardResult::CARD_RESULT_NOFILE) + { + info.first = 1; + continue; + } + else if (result == ECardResult::CARD_RESULT_READY) + { + CMemoryCardSys::CARDStat stat = {}; + if (CMemoryCardSys::GetStatus(x0_cardPort, info.second.GetFileNo(), stat) == + ECardResult::CARD_RESULT_READY) + { + u32 comment = stat.GetCommentAddr(); + if (comment == -1) + info.first = 3; + else + info.first = 2; + } + else + { + NoCardFound(); + return; + } + if (info.second.Close() == ECardResult::CARD_RESULT_NOCARD) + { + NoCardFound(); + return; + } + } + else + { + NoCardFound(); + return; + } + } + } + if (x100_mcFileInfos[0].first == 2) + { + if (x100_mcFileInfos[1].first == 2) + { + CMemoryCardSys::CARDStat stat = {}; + if (CMemoryCardSys::GetStatus(x0_cardPort, x100_mcFileInfos[0].second.GetFileNo(), stat) == + ECardResult::CARD_RESULT_READY) + { + u32 timeA = stat.GetTime(); + if (CMemoryCardSys::GetStatus(x0_cardPort, x100_mcFileInfos[1].second.GetFileNo(), stat) == + ECardResult::CARD_RESULT_READY) + { + u32 timeB = stat.GetTime(); + if (timeA > timeB) + x194_fileIdx = 0; + else + x194_fileIdx = 1; + GoTo29(); + return; + } + NoCardFound(); + return; + } + NoCardFound(); + return; + } + x194_fileIdx = 0; + GoTo29(); + return; + } + + if (x100_mcFileInfos[1].first == 2) + { + x194_fileIdx = 1; + GoTo29(); + return; + } + + if (x100_mcFileInfos[0].first == 3 || x100_mcFileInfos[1].first == 3) + { + x10_state = EState::Seventeen; + x14_error = EError::Nine; + } + else + { + x10_state = EState::Seventeen; + x14_error = EError::Eight; + } } void CMemoryCardDriver::GoTo28() { + x14_error = EError::Zero; + x10_state = EState::TwentyEight; + int idx = 0; + for (std::pair& info : x100_mcFileInfos) + { + if (info.first == 3) + { + x194_fileIdx = idx; + ECardResult result = CMemoryCardSys::FastDeleteFile(x0_cardPort, info.second.GetFileNo()); + if (result != ECardResult::CARD_RESULT_READY) + { + Case28(result); + return; + } + } + ++idx; + } +} +void CMemoryCardDriver::GoTo29() +{ + x14_error = EError::Zero; + x10_state = EState::TwentyNine; + ECardResult result = x100_mcFileInfos[x194_fileIdx].second.Open(); + if (result != ECardResult::CARD_RESULT_READY) + { + Case29(result); + return; + } + + result = x100_mcFileInfos[x194_fileIdx].second.StartRead(); + if (result != ECardResult::CARD_RESULT_READY) + Case29(result); +} + +void CMemoryCardDriver::GoTo32() +{ + x14_error = EError::Zero; + x10_state = EState::Write; + ECardResult result = x198_fileInfo->Write(); + if (result != ECardResult::CARD_RESULT_READY) + Case32(result); +} + +void CMemoryCardDriver::GoTo33() +{ + x14_error = EError::Zero; + x10_state = EState::ThirtyThree; + ClearFileInfo(); + if (x18_cardFreeBytes < 8192 || !x1c_cardFreeFiles) + { + x10_state = EState::Twenty; + x14_error = EError::Five; + return; + } + + x198_fileInfo = std::make_unique(x0_cardPort, SaveFileNames[x194_fileIdx]); + InitializeFileInfo(); + ECardResult result = x198_fileInfo->CreateFile(); + if (result != ECardResult::CARD_RESULT_READY) + Case33(result); +} + +void CMemoryCardDriver::GoTo34() +{ + x14_error = EError::Zero; + x10_state = EState::ThirtyFour; + ECardResult result = x198_fileInfo->Write(); + if (result != ECardResult::CARD_RESULT_READY) + Case34(result); +} + +void CMemoryCardDriver::GoTo35() +{ + x14_error = EError::Zero; + x10_state = EState::ThirtyFive; + ECardResult result = CMemoryCardSys::DeleteFile(x0_cardPort, + SaveFileNames[!bool(x194_fileIdx)]); + if (result != ECardResult::CARD_RESULT_READY) + Case35(result); +} + +void CMemoryCardDriver::GoTo36() +{ + if (x194_fileIdx == 1) + { + x14_error = EError::Zero; + x10_state = EState::ThirtySix; + ECardResult result = CMemoryCardSys::Rename(x0_cardPort, + SaveFileNames[x194_fileIdx], + SaveFileNames[!bool(x194_fileIdx)]); + if (result != ECardResult::CARD_RESULT_READY) + Case36(result); + } + else + { + x10_state = EState::RuntimeBackup; + WriteBackupBuf(); + } +} + +void CMemoryCardDriver::GoTo37() +{ + x14_error = EError::Zero; + x10_state = EState::CardFormat; + ECardResult result = CMemoryCardSys::FormatCard(x0_cardPort); + if (result != ECardResult::CARD_RESULT_READY) + Case37(result); +} + +void CMemoryCardDriver::InitializeFileInfo() +{ + ExportPersistentOptions(); + /* TODO: Finish */ +} + +void CMemoryCardDriver::WriteBackupBuf() +{ + g_GameState->WriteBackupBuf(); + g_GameState->SetCardSerial(x28_cardSerial); } bool CMemoryCardDriver::GetCardFreeBytes() @@ -451,7 +781,7 @@ void CMemoryCardDriver::Update() if (result.x0_error == ECardResult::CARD_RESULT_NOCARD) { - if (x10_state != EState::Two) + if (x10_state != EState::NoCard) NoCardFound(); static_cast(g_Main)->SetCardInserted(false); return; @@ -474,7 +804,7 @@ void CMemoryCardDriver::Update() switch (x10_state) { - case EState::TwentySix: + case EState::CardMount: Case26(resultCode); break; case EState::TwentySeven: @@ -492,7 +822,7 @@ void CMemoryCardDriver::Update() case EState::ThirtyOne: Case31(resultCode); break; - case EState::ThirtyTwo: + case EState::Write: Case32(resultCode); break; case EState::ThirtyThree: @@ -507,7 +837,7 @@ void CMemoryCardDriver::Update() case EState::ThirtySix: Case36(resultCode); break; - case EState::ThirtySeven: + case EState::CardFormat: Case37(resultCode); break; default: break; diff --git a/Runtime/MP1/CMemoryCardDriver.hpp b/Runtime/MP1/CMemoryCardDriver.hpp index e1aa74884..144e7dec7 100644 --- a/Runtime/MP1/CMemoryCardDriver.hpp +++ b/Runtime/MP1/CMemoryCardDriver.hpp @@ -15,30 +15,44 @@ class CMemoryCardDriver public: enum class EState { - Zero, - One = 1, - Two = 2, - Five = 5, - Six = 6, - Seven = 7, + Initial, + Ready = 1, + NoCard = 2, + RuntimeBackup = 3, + CardFormatted = 4, + CardNeedsMount = 5, + CardMountDone = 6, + SelectCardFile = 7, + WillWrite = 8, + Nine = 9, + Ten = 10, + Eleven = 11, Twelve = 12, Thirteen = 13, Fourteen = 14, Fifteen = 15, + Sixteen = 16, Seventeen = 17, - TwentyFive = 26, - TwentySix = 26, + Eighteen = 18, + Nineteen = 19, + Twenty = 20, + TwentyOne = 21, + TwentyTwo = 22, + TwentyThree = 23, + CardFormatBroken = 24, + TwentyFive = 25, + CardMount = 26, TwentySeven = 27, TwentyEight = 28, TwentyNine = 29, Thirty = 30, ThirtyOne = 31, - ThirtyTwo = 32, + Write = 32, ThirtyThree = 33, ThirtyFour = 34, ThirtyFive = 35, ThirtySix = 36, - ThirtySeven = 37 + CardFormat = 37 }; enum class EError @@ -72,9 +86,11 @@ private: 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); @@ -99,7 +115,7 @@ private: ResId x4_saveBanner; ResId x8_saveIcon0; ResId xc_saveIcon1; - EState x10_state = EState::Zero; + EState x10_state = EState::Initial; EError x14_error = EError::Zero; s32 x18_cardFreeBytes = 0; s32 x1c_cardFreeFiles = 0; @@ -110,13 +126,13 @@ private: std::unique_ptr xe4_fileSlots[3]; std::vector> x100_mcFileInfos; u32 x194_fileIdx = -1; - u32 x198_ = 0; + std::unique_ptr x198_fileInfo; bool x19c_ = false; - bool x19d_doMergePersistent; + bool x19d_doImportPersistent; public: CMemoryCardDriver(CMemoryCardSys::EMemoryCardPort cardPort, ResId saveBanner, - ResId saveIcon0, ResId saveIcon1, bool flag); + ResId saveIcon0, ResId saveIcon1, bool importPersistent); void FinishedLoading(); void FinishedLoading2(); void NoCardFound(); @@ -127,7 +143,8 @@ public: static SSaveHeader LoadSaveHeader(CMemoryInStream& in); static std::unique_ptr LoadSaveFile(CMemoryInStream& in); void ReadFinished(); - void MergePersistentOptions(); + void ImportPersistentOptions(); + void ExportPersistentOptions(); void DeleteFile(); void CheckCardCapacity(); @@ -146,14 +163,24 @@ public: void GoTo17(); void GoTo28(); + void GoTo29(); + void GoTo32(); + void GoTo33(); + void GoTo34(); + void GoTo35(); + void GoTo36(); + void GoTo37(); + void ClearFileInfo() { x198_fileInfo.reset(); } + void InitializeFileInfo(); + void WriteBackupBuf(); bool GetCardFreeBytes(); void HandleCardError(CMemoryCardSys::ECardResult result, EState state); void Update(); static bool InCardInsertedRange(EState v) { - return v >= EState::TwentySix && v <= EState::ThirtySeven; + return v >= EState::CardMount && v <= EState::CardFormat; } static bool InRange2(EState v) diff --git a/Runtime/MP1/CSaveUI.cpp b/Runtime/MP1/CSaveUI.cpp index 5d9fa9933..f5cfadbf0 100644 --- a/Runtime/MP1/CSaveUI.cpp +++ b/Runtime/MP1/CSaveUI.cpp @@ -59,7 +59,7 @@ bool CSaveUI::PumpLoad() CSaveUI::UIType CSaveUI::SelectUIType() const { - if (x6c_cardDriver->x10_state == EState::Two) + if (x6c_cardDriver->x10_state == EState::NoCard) return UIType::Three; switch (x10_uiType) @@ -78,7 +78,7 @@ CSaveUI::UIType CSaveUI::SelectUIType() const return UIType::One; } - if (x6c_cardDriver->x10_state == EState::One) + if (x6c_cardDriver->x10_state == EState::Ready) { if (x6c_cardDriver->x14_error == CMemoryCardDriver::EError::Six) return UIType::Twelve; diff --git a/Runtime/Particle/CDecalDataFactory.cpp b/Runtime/Particle/CDecalDataFactory.cpp index f00509e1c..077101ed0 100644 --- a/Runtime/Particle/CDecalDataFactory.cpp +++ b/Runtime/Particle/CDecalDataFactory.cpp @@ -139,7 +139,7 @@ void CDecalDataFactory::GetQuadDecalInfo(CInputStream& in, CSimplePool* resPool, CFactoryFnReturn FDecalDataFactory(const SObjectTag &tag, CInputStream &in, const CVParamTransfer &vparms) { - CSimplePool* sp = static_cast(static_cast*>(vparms.GetObj())->GetParam()); + CSimplePool* sp = vparms.GetOwnedObj(); return TToken::GetIObjObjectFor(std::unique_ptr(CDecalDataFactory::GetGeneratorDesc(in, sp))); } diff --git a/Runtime/Particle/CParticleDataFactory.cpp b/Runtime/Particle/CParticleDataFactory.cpp index 1c8438bd2..8968175b7 100644 --- a/Runtime/Particle/CParticleDataFactory.cpp +++ b/Runtime/Particle/CParticleDataFactory.cpp @@ -1160,7 +1160,7 @@ CFactoryFnReturn FParticleFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms, CObjectReference* selfRef) { - CSimplePool* sp = static_cast(static_cast*>(vparms.GetObj())->GetParam()); + CSimplePool* sp = vparms.GetOwnedObj(); return TToken::GetIObjObjectFor(std::unique_ptr(CParticleDataFactory::GetGeneratorDesc(in, sp))); } diff --git a/Runtime/Particle/CParticleElectricDataFactory.cpp b/Runtime/Particle/CParticleElectricDataFactory.cpp index 7636f82c4..326f3452a 100644 --- a/Runtime/Particle/CParticleElectricDataFactory.cpp +++ b/Runtime/Particle/CParticleElectricDataFactory.cpp @@ -134,7 +134,7 @@ void CParticleElectricDataFactory::LoadELSMTokens(CElectricDescription* desc) CFactoryFnReturn FParticleElectricDataFactory(const SObjectTag &tag, CInputStream &in, const CVParamTransfer &vparms) { - CSimplePool* sp = static_cast(static_cast*>(vparms.GetObj())->GetParam()); + CSimplePool* sp = vparms.GetOwnedObj(); return TToken::GetIObjObjectFor(std::unique_ptr(CParticleElectricDataFactory::GetGeneratorDesc(in, sp))); } diff --git a/Runtime/Particle/CParticleSwooshDataFactory.cpp b/Runtime/Particle/CParticleSwooshDataFactory.cpp index 6f0334ffc..c00878b17 100644 --- a/Runtime/Particle/CParticleSwooshDataFactory.cpp +++ b/Runtime/Particle/CParticleSwooshDataFactory.cpp @@ -139,7 +139,7 @@ bool CParticleSwooshDataFactory::CreateWPSM(CSwooshDescription* desc, CInputStre CFactoryFnReturn FParticleSwooshDataFactory(const SObjectTag &tag, CInputStream &in, const CVParamTransfer &vparms) { - CSimplePool* sp = static_cast(static_cast*>(vparms.GetObj())->GetParam()); + CSimplePool* sp = vparms.GetOwnedObj(); return TToken::GetIObjObjectFor(std::unique_ptr(CParticleSwooshDataFactory::GetGeneratorDesc(in, sp))); } diff --git a/Runtime/Particle/CProjectileWeaponDataFactory.cpp b/Runtime/Particle/CProjectileWeaponDataFactory.cpp index 8656849cc..1fddeafcb 100644 --- a/Runtime/Particle/CProjectileWeaponDataFactory.cpp +++ b/Runtime/Particle/CProjectileWeaponDataFactory.cpp @@ -166,7 +166,7 @@ bool CProjectileWeaponDataFactory::CreateWPSM(CWeaponDescription* desc, CInputSt CFactoryFnReturn FProjectileWeaponDataFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms) { - CSimplePool* sp = static_cast(static_cast*>(vparms.GetObj())->GetParam()); + CSimplePool* sp = vparms.GetOwnedObj(); return TToken::GetIObjObjectFor(std::unique_ptr(CProjectileWeaponDataFactory::GetGeneratorDesc(in, sp))); }