mirror of https://github.com/AxioDL/metaforce.git
Work on CMemoryCardDriver
This commit is contained in:
parent
c92223301c
commit
d7f79d6ec3
|
@ -12,6 +12,21 @@ namespace urde
|
||||||
|
|
||||||
using OSTime = s64;
|
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
|
class CBasics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -23,6 +38,8 @@ public:
|
||||||
|
|
||||||
static OSTime ToWiiTime(std::chrono::system_clock::time_point time);
|
static OSTime ToWiiTime(std::chrono::system_clock::time_point time);
|
||||||
static std::chrono::system_clock::time_point FromWiiTime(OSTime wiiTime);
|
static std::chrono::system_clock::time_point FromWiiTime(OSTime wiiTime);
|
||||||
|
|
||||||
|
static OSCalendarTime ToCalendarTime(OSTime time);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,4 +59,11 @@ std::chrono::system_clock::time_point CBasics::FromWiiTime(OSTime wiiTime)
|
||||||
return std::chrono::system_clock::from_time_t(time - tzDiff);
|
return std::chrono::system_clock::from_time_t(time - tzDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OSCalendarTime CBasics::ToCalendarTime(OSTime time)
|
||||||
|
{
|
||||||
|
OSCalendarTime ret = {};
|
||||||
|
/* TODO: Finsh */
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<CSaveWorld> 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<ResId, TEditorId>& pair) -> bool
|
||||||
|
{
|
||||||
|
return pair.first == mlvlId && pair.second == cineId;
|
||||||
|
});
|
||||||
|
|
||||||
|
return existing != xac_cinematicStates.cend();
|
||||||
|
}
|
||||||
|
|
||||||
void CPersistentOptions::SetCinematicState(ResId mlvlId, TEditorId cineId, bool state)
|
void CPersistentOptions::SetCinematicState(ResId mlvlId, TEditorId cineId, bool state)
|
||||||
{
|
{
|
||||||
auto existing = std::find_if(xac_cinematicStates.cbegin(), xac_cinematicStates.cend(),
|
auto existing = std::find_if(xac_cinematicStates.cbegin(), xac_cinematicStates.cend(),
|
||||||
|
|
|
@ -40,6 +40,7 @@ public:
|
||||||
CPersistentOptions() = default;
|
CPersistentOptions() = default;
|
||||||
CPersistentOptions(CBitStreamReader& stream);
|
CPersistentOptions(CBitStreamReader& stream);
|
||||||
|
|
||||||
|
bool GetCinematicState(ResId mlvlId, TEditorId cineId) const;
|
||||||
void SetCinematicState(ResId mlvlId, TEditorId cineId, bool state);
|
void SetCinematicState(ResId mlvlId, TEditorId cineId, bool state);
|
||||||
bool GetPlayerHasHardMode() const { return xd0_25_hasHardMode; }
|
bool GetPlayerHasHardMode() const { return xd0_25_hasHardMode; }
|
||||||
void SetPlayerHasHardMode(bool v) { xd0_25_hasHardMode = v; }
|
void SetPlayerHasHardMode(bool v) { xd0_25_hasHardMode = v; }
|
||||||
|
@ -51,6 +52,7 @@ public:
|
||||||
void SetAllItemsCollected(bool v) { xd0_29_allItemsCollected = v; }
|
void SetAllItemsCollected(bool v) { xd0_29_allItemsCollected = v; }
|
||||||
u32 GetLogScanCount() const { return xcc_logScanCount; }
|
u32 GetLogScanCount() const { return xcc_logScanCount; }
|
||||||
void SetLogScanCount(u32 v) { xcc_logScanCount = v; }
|
void SetLogScanCount(u32 v) { xcc_logScanCount = v; }
|
||||||
|
void PutTo(CBitStreamWriter& w) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Options tracked per game session */
|
/** Options tracked per game session */
|
||||||
|
|
|
@ -183,7 +183,7 @@ CGameState::CGameState(CBitStreamReader& stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameState::MergePersistentOptions(const CPersistentOptions& opts)
|
void CGameState::ImportPersistentOptions(const CPersistentOptions& opts)
|
||||||
{
|
{
|
||||||
if (opts.xd0_24_)
|
if (opts.xd0_24_)
|
||||||
xa8_systemOptions.xd0_24_ = true;
|
xa8_systemOptions.xd0_24_ = true;
|
||||||
|
@ -197,6 +197,24 @@ void CGameState::MergePersistentOptions(const CPersistentOptions& opts)
|
||||||
xa8_systemOptions.SetPlayerBeatHardMode(opts.GetPlayerBeatHardMode());
|
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
|
void CGameState::PutTo(CBitStreamWriter& writer) const
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < 128; i++)
|
for (u32 i = 0; i < 128; i++)
|
||||||
|
|
|
@ -80,8 +80,8 @@ class CGameState
|
||||||
CPersistentOptions xa8_systemOptions;
|
CPersistentOptions xa8_systemOptions;
|
||||||
CGameOptions x17c_gameOptions;
|
CGameOptions x17c_gameOptions;
|
||||||
CHintOptions x1f8_hintOptions;
|
CHintOptions x1f8_hintOptions;
|
||||||
u32 x210_;
|
u64 x210_cardSerial;
|
||||||
u32 x214_;
|
std::vector<u8> x218_backupBuf;
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
@ -108,7 +108,10 @@ public:
|
||||||
CWorldState& CurrentWorldState() { return StateForWorld(x84_mlvlId); }
|
CWorldState& CurrentWorldState() { return StateForWorld(x84_mlvlId); }
|
||||||
ResId CurrentWorldAssetId() const { return x84_mlvlId; }
|
ResId CurrentWorldAssetId() const { return x84_mlvlId; }
|
||||||
void SetHardMode(bool v) { x228_24_hardMode = v; }
|
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;
|
void PutTo(CBitStreamWriter& writer) const;
|
||||||
|
|
||||||
struct GameFileStateInfo
|
struct GameFileStateInfo
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "CSimplePool.hpp"
|
#include "CSimplePool.hpp"
|
||||||
#include "CGameState.hpp"
|
#include "CGameState.hpp"
|
||||||
#include "GuiSys/CStringTable.hpp"
|
#include "GuiSys/CStringTable.hpp"
|
||||||
|
#include "CCRC32.hpp"
|
||||||
|
#include "Graphics/CTexture.hpp"
|
||||||
|
|
||||||
namespace urde
|
namespace urde
|
||||||
{
|
{
|
||||||
|
@ -132,6 +134,199 @@ bool CMemoryCardSys::InitializePump()
|
||||||
return false;
|
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<u32&>(*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<CTexture>& tex = *x40_bannerTok;
|
||||||
|
u32 bufSz;
|
||||||
|
ETexelFormat fmt;
|
||||||
|
std::unique_ptr<u8[]> palette;
|
||||||
|
std::unique_ptr<u8[]> 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<u8[]> palette;
|
||||||
|
for (const Icon& icon : x50_iconToks)
|
||||||
|
{
|
||||||
|
u32 bufSz;
|
||||||
|
ETexelFormat fmt;
|
||||||
|
std::unique_ptr<u8[]> 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)
|
CMemoryCardSys::CardProbeResults CMemoryCardSys::CardProbe(EMemoryCardPort port)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
|
@ -167,6 +362,11 @@ CMemoryCardSys::ECardResult CMemoryCardSys::GetStatus(EMemoryCardPort port, int
|
||||||
return ECardResult::CARD_RESULT_READY;
|
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)
|
CMemoryCardSys::ECardResult CMemoryCardSys::DeleteFile(EMemoryCardPort port, const char* name)
|
||||||
{
|
{
|
||||||
return ECardResult::CARD_RESULT_READY;
|
return ECardResult::CARD_RESULT_READY;
|
||||||
|
@ -177,4 +377,14 @@ CMemoryCardSys::ECardResult CMemoryCardSys::FastDeleteFile(EMemoryCardPort port,
|
||||||
return ECardResult::CARD_RESULT_READY;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace urde
|
||||||
{
|
{
|
||||||
class CDummyWorld;
|
class CDummyWorld;
|
||||||
class CStringTable;
|
class CStringTable;
|
||||||
|
class CSimplePool;
|
||||||
|
|
||||||
class CSaveWorldMemory
|
class CSaveWorldMemory
|
||||||
{
|
{
|
||||||
|
@ -79,6 +80,7 @@ public:
|
||||||
CARD_RESULT_ENCODING = -13,
|
CARD_RESULT_ENCODING = -13,
|
||||||
CARD_RESULT_BROKEN = -6,
|
CARD_RESULT_BROKEN = -6,
|
||||||
CARD_RESULT_IOERROR = -5,
|
CARD_RESULT_IOERROR = -5,
|
||||||
|
CARD_RESULT_NOFILE = -4,
|
||||||
CARD_RESULT_NOCARD = -3,
|
CARD_RESULT_NOCARD = -3,
|
||||||
CARD_RESULT_WRONGDEVICE = -2,
|
CARD_RESULT_WRONGDEVICE = -2,
|
||||||
CARD_RESULT_BUSY = -1,
|
CARD_RESULT_BUSY = -1,
|
||||||
|
@ -116,6 +118,7 @@ public:
|
||||||
u32 x64_offsetIconTlut;
|
u32 x64_offsetIconTlut;
|
||||||
u32 x68_offsetData;
|
u32 x68_offsetData;
|
||||||
|
|
||||||
|
u32 GetFileLength() const { return x20_length; }
|
||||||
u32 GetTime() const { return x24_time; }
|
u32 GetTime() const { return x24_time; }
|
||||||
u32 GetBannerFormat() const { return x2e_bannerFormat & 0x3; }
|
u32 GetBannerFormat() const { return x2e_bannerFormat & 0x3; }
|
||||||
void SetBannerFormat(u32 fmt) { x2e_bannerFormat = (x2e_bannerFormat & ~0x3) | fmt; }
|
void SetBannerFormat(u32 fmt) { x2e_bannerFormat = (x2e_bannerFormat & ~0x3) | fmt; }
|
||||||
|
@ -136,6 +139,68 @@ public:
|
||||||
void SetCommentAddr(u32 addr) { x38_commentAddr = addr; }
|
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<CTexture> 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<TLockedToken<CTexture>> x40_bannerTok;
|
||||||
|
rstl::reserved_vector<Icon, 8> x50_iconToks;
|
||||||
|
std::vector<u8> xf4_saveBuffer;
|
||||||
|
std::vector<u8> x104_cardBuffer;
|
||||||
|
|
||||||
|
CVParamTransfer m_texParam = {new TObjOwnerParam<u32>(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 CardProbeResults CardProbe(EMemoryCardPort port);
|
||||||
static ECardResult MountCard(EMemoryCardPort port);
|
static ECardResult MountCard(EMemoryCardPort port);
|
||||||
static ECardResult CheckCard(EMemoryCardPort port);
|
static ECardResult CheckCard(EMemoryCardPort port);
|
||||||
|
@ -143,8 +208,11 @@ public:
|
||||||
static ECardResult GetSerialNo(EMemoryCardPort port, u64& serialOut);
|
static ECardResult GetSerialNo(EMemoryCardPort port, u64& serialOut);
|
||||||
static ECardResult GetResultCode(EMemoryCardPort port);
|
static ECardResult GetResultCode(EMemoryCardPort port);
|
||||||
static ECardResult GetStatus(EMemoryCardPort port, int fileNo, CARDStat& statOut);
|
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 DeleteFile(EMemoryCardPort port, const char* name);
|
||||||
static ECardResult FastDeleteFile(EMemoryCardPort port, int fileNo);
|
static ECardResult FastDeleteFile(EMemoryCardPort port, int fileNo);
|
||||||
|
static ECardResult Rename(EMemoryCardPort port, const char* oldName, const char* newName);
|
||||||
|
static ECardResult FormatCard(EMemoryCardPort port);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,9 +72,7 @@ CFactoryFnReturn AnimSourceFactory(const SObjectTag& tag, CInputStream& in,
|
||||||
const CVParamTransfer& params,
|
const CVParamTransfer& params,
|
||||||
CObjectReference* selfRef)
|
CObjectReference* selfRef)
|
||||||
{
|
{
|
||||||
CSimplePool* sp = static_cast<CSimplePool*>(
|
CSimplePool* sp = params.GetOwnedObj<CSimplePool*>();
|
||||||
static_cast<TObjOwnerParam<IObjectStore*>*>(
|
|
||||||
params.GetObj())->GetParam());
|
|
||||||
return TToken<CAllFormatsAnimSource>::GetIObjObjectFor(
|
return TToken<CAllFormatsAnimSource>::GetIObjObjectFor(
|
||||||
std::make_unique<CAllFormatsAnimSource>(in, *sp, tag));
|
std::make_unique<CAllFormatsAnimSource>(in, *sp, tag));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,7 @@ CFactoryFnReturn CCharacterFactory::CDummyFactory::Build(const SObjectTag& tag,
|
||||||
CObjectReference* selfRef)
|
CObjectReference* selfRef)
|
||||||
{
|
{
|
||||||
|
|
||||||
const CCharacterInfo& charInfo =
|
const CCharacterInfo& charInfo = *params.GetOwnedObj<const CCharacterInfo*>();
|
||||||
*static_cast<TObjOwnerParam<const CCharacterInfo*>&>(*params.GetObj()).GetParam();
|
|
||||||
|
|
||||||
switch (tag.type.toUint32() & 0x1)
|
switch (tag.type.toUint32() & 0x1)
|
||||||
{
|
{
|
||||||
|
|
|
@ -284,7 +284,7 @@ FourCC CCollisionResponseData::UncookedResType()
|
||||||
|
|
||||||
CFactoryFnReturn FCollisionResponseDataFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms)
|
CFactoryFnReturn FCollisionResponseDataFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms)
|
||||||
{
|
{
|
||||||
CSimplePool* sp = static_cast<CSimplePool*>(static_cast<TObjOwnerParam<IObjectStore*>*>(vparms.GetObj())->GetParam());
|
CSimplePool* sp = vparms.GetOwnedObj<CSimplePool*>();
|
||||||
return TToken<CCollisionResponseData>::GetIObjObjectFor(std::unique_ptr<CCollisionResponseData>(new CCollisionResponseData(in, sp)));
|
return TToken<CCollisionResponseData>::GetIObjObjectFor(std::unique_ptr<CCollisionResponseData>(new CCollisionResponseData(in, sp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "Graphics/CBooRenderer.hpp"
|
#include "Graphics/CBooRenderer.hpp"
|
||||||
#include "Character/CSkinRules.hpp"
|
#include "Character/CSkinRules.hpp"
|
||||||
#include "GameGlobalObjects.hpp"
|
#include "GameGlobalObjects.hpp"
|
||||||
|
#include "CSimplePool.hpp"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace urde
|
namespace urde
|
||||||
|
@ -807,8 +808,8 @@ CFactoryFnReturn FModelFactory(const urde::SObjectTag& tag,
|
||||||
const urde::CVParamTransfer& vparms,
|
const urde::CVParamTransfer& vparms,
|
||||||
CObjectReference* selfRef)
|
CObjectReference* selfRef)
|
||||||
{
|
{
|
||||||
IObjectStore* store = static_cast<TObjOwnerParam<IObjectStore*>*>(vparms.GetObj())->GetParam();
|
CSimplePool* sp = vparms.GetOwnedObj<CSimplePool*>();
|
||||||
CFactoryFnReturn ret = TToken<CModel>::GetIObjObjectFor(std::make_unique<CModel>(std::move(in), len, store, selfRef));
|
CFactoryFnReturn ret = TToken<CModel>::GetIObjObjectFor(std::make_unique<CModel>(std::move(in), len, sp, selfRef));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ class CTexture
|
||||||
boo::GraphicsDataToken m_booToken;
|
boo::GraphicsDataToken m_booToken;
|
||||||
boo::ITexture* m_booTex;
|
boo::ITexture* m_booTex;
|
||||||
boo::ITexture* m_paletteTex;
|
boo::ITexture* m_paletteTex;
|
||||||
|
std::unique_ptr<u8[]> m_otex;
|
||||||
|
|
||||||
size_t ComputeMippedTexelCount();
|
size_t ComputeMippedTexelCount();
|
||||||
size_t ComputeMippedBlockCountDXT1();
|
size_t ComputeMippedBlockCountDXT1();
|
||||||
|
@ -39,18 +40,22 @@ class CTexture
|
||||||
void BuildC8(const void* data, size_t length);
|
void BuildC8(const void* data, size_t length);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CTexture(std::unique_ptr<u8[]>&& in, u32 length);
|
CTexture(std::unique_ptr<u8[]>&& in, u32 length, bool otex);
|
||||||
enum class EClampMode
|
enum class EClampMode
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
One
|
One
|
||||||
};
|
};
|
||||||
ETexelFormat GetTexelFormat() const {return x0_fmt;}
|
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 GetWidth() const {return x4_w;}
|
||||||
u16 GetHeight() const {return x6_h;}
|
u16 GetHeight() const {return x6_h;}
|
||||||
void Load(int slot, EClampMode clamp) const;
|
void Load(int slot, EClampMode clamp) const;
|
||||||
boo::ITexture* GetBooTexture() {return m_booTex;}
|
boo::ITexture* GetBooTexture() {return m_booTex;}
|
||||||
boo::ITexture* GetPaletteTexture() {return m_paletteTex;}
|
boo::ITexture* GetPaletteTexture() {return m_paletteTex;}
|
||||||
|
std::unique_ptr<u8[]> BuildMemoryCardTex(u32& sizeOut, ETexelFormat& fmtOut,
|
||||||
|
std::unique_ptr<u8[]>& paletteOut) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
CFactoryFnReturn FTextureFactory(const urde::SObjectTag& tag,
|
CFactoryFnReturn FTextureFactory(const urde::SObjectTag& tag,
|
||||||
|
|
|
@ -684,7 +684,7 @@ void CTexture::BuildC8(const void* data, size_t length)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
CTexture::CTexture(std::unique_ptr<u8[]>&& in, u32 length)
|
CTexture::CTexture(std::unique_ptr<u8[]>&& in, u32 length, bool otex)
|
||||||
{
|
{
|
||||||
std::unique_ptr<u8[]> owned = std::move(in);
|
std::unique_ptr<u8[]> owned = std::move(in);
|
||||||
athena::io::MemoryReader r(owned.get(), length);
|
athena::io::MemoryReader r(owned.get(), length);
|
||||||
|
@ -737,6 +737,9 @@ CTexture::CTexture(std::unique_ptr<u8[]>&& in, u32 length)
|
||||||
default:
|
default:
|
||||||
Log.report(logvisor::Fatal, "invalid texture type %d for boo", int(x0_fmt));
|
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
|
void CTexture::Load(int slot, EClampMode clamp) const
|
||||||
|
@ -744,12 +747,125 @@ void CTexture::Load(int slot, EClampMode clamp) const
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<u8[]> CTexture::BuildMemoryCardTex(u32& sizeOut, ETexelFormat& fmtOut,
|
||||||
|
std::unique_ptr<u8[]>& 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<u8[]> ret;
|
||||||
|
if (x0_fmt == ETexelFormat::RGBA8PC)
|
||||||
|
{
|
||||||
|
sizeOut = texelCount * 2;
|
||||||
|
fmtOut = ETexelFormat::RGB5A3;
|
||||||
|
ret.reset(new u8[sizeOut]);
|
||||||
|
u16* texel = reinterpret_cast<u16*>(ret.get());
|
||||||
|
|
||||||
|
int w = x4_w;
|
||||||
|
int h = x6_h;
|
||||||
|
const RGBA8* sourceMip = reinterpret_cast<const RGBA8*>(m_otex.get() + 12);
|
||||||
|
int bwidth = (w + 3) / 4;
|
||||||
|
int bheight = (h + 3) / 4;
|
||||||
|
for (int by=0 ; by<bheight ; ++by)
|
||||||
|
{
|
||||||
|
int baseY = by * 4;
|
||||||
|
for (int bx=0 ; bx<bwidth ; ++bx)
|
||||||
|
{
|
||||||
|
int baseX = bx * 4;
|
||||||
|
for (int y=0 ; y<4 ; ++y)
|
||||||
|
{
|
||||||
|
const RGBA8* source = sourceMip + (baseY + y) * w + baseX;
|
||||||
|
for (int x=0 ; x<4 ; ++x)
|
||||||
|
{
|
||||||
|
if (source[x].a == 0xff)
|
||||||
|
{
|
||||||
|
*texel++ = hecl::SBig(u16((source[x].r >> 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<u16*>(paletteOut.get());
|
||||||
|
|
||||||
|
int w = x4_w;
|
||||||
|
int h = x6_h;
|
||||||
|
const u8* data = m_otex.get() + 12;
|
||||||
|
u32 nentries = hecl::SBig(*reinterpret_cast<const u32*>(data));
|
||||||
|
const RGBA8* paletteTexels = reinterpret_cast<const RGBA8*>(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<bheight ; ++by)
|
||||||
|
{
|
||||||
|
int baseY = by * 4;
|
||||||
|
for (int bx=0 ; bx<bwidth ; ++bx)
|
||||||
|
{
|
||||||
|
int baseX = bx * 8;
|
||||||
|
for (int y=0 ; y<4 ; ++y)
|
||||||
|
{
|
||||||
|
const u8* source = sourceMip + (baseY + y) * w + baseX;
|
||||||
|
for (int x=0 ; x<8 ; ++x)
|
||||||
|
*texel++ = source[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log.report(logvisor::Fatal, "MemoryCard texture may only use RGBA8PC or C8PC format");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
CFactoryFnReturn FTextureFactory(const urde::SObjectTag& tag,
|
CFactoryFnReturn FTextureFactory(const urde::SObjectTag& tag,
|
||||||
std::unique_ptr<u8[]>&& in, u32 len,
|
std::unique_ptr<u8[]>&& in, u32 len,
|
||||||
const urde::CVParamTransfer& vparms,
|
const urde::CVParamTransfer& vparms,
|
||||||
CObjectReference* selfRef)
|
CObjectReference* selfRef)
|
||||||
{
|
{
|
||||||
return TToken<CTexture>::GetIObjObjectFor(std::make_unique<CTexture>(std::move(in), len));
|
return TToken<CTexture>::GetIObjObjectFor(std::make_unique<CTexture>(std::move(in), len,
|
||||||
|
vparms.GetOwnedObj<u32>() == SBIG('OTEX')));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,7 @@ std::unique_ptr<IObj> RGuiFrameFactoryInGame(const SObjectTag& tag, CInputStream
|
||||||
const CVParamTransfer& cvParms,
|
const CVParamTransfer& cvParms,
|
||||||
CObjectReference* selfRef)
|
CObjectReference* selfRef)
|
||||||
{
|
{
|
||||||
CSimplePool* sp = static_cast<CSimplePool*>(static_cast<TObjOwnerParam<IObjectStore*>*>(cvParms.GetObj())->GetParam());
|
CSimplePool* sp = cvParms.GetOwnedObj<CSimplePool*>();
|
||||||
std::unique_ptr<CGuiFrame> frame(CGuiFrame::CreateFrame(tag.id, *g_GuiSys, in, sp));
|
std::unique_ptr<CGuiFrame> frame(CGuiFrame::CreateFrame(tag.id, *g_GuiSys, in, sp));
|
||||||
return TToken<CGuiFrame>::GetIObjObjectFor(std::move(frame));
|
return TToken<CGuiFrame>::GetIObjObjectFor(std::move(frame));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "CDrawStringOptions.hpp"
|
#include "CDrawStringOptions.hpp"
|
||||||
#include "CTextRenderBuffer.hpp"
|
#include "CTextRenderBuffer.hpp"
|
||||||
#include "Graphics/CTexture.hpp"
|
#include "Graphics/CTexture.hpp"
|
||||||
|
#include "CSimplePool.hpp"
|
||||||
|
|
||||||
namespace urde
|
namespace urde
|
||||||
{
|
{
|
||||||
|
@ -195,8 +196,8 @@ void CRasterFont::GetSize(const CDrawStringOptions& opts, int& width, int& heigh
|
||||||
std::unique_ptr<IObj> FRasterFontFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms,
|
std::unique_ptr<IObj> FRasterFontFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms,
|
||||||
CObjectReference* selfRef)
|
CObjectReference* selfRef)
|
||||||
{
|
{
|
||||||
return TToken<CRasterFont>::GetIObjObjectFor(
|
CSimplePool* sp = vparms.GetOwnedObj<CSimplePool*>();
|
||||||
std::make_unique<CRasterFont>(in, *static_cast<TObjOwnerParam<IObjectStore*>*>(vparms.GetObj())->GetParam()));
|
return TToken<CRasterFont>::GetIObjObjectFor(std::make_unique<CRasterFont>(in, *sp));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,15 @@ public:
|
||||||
virtual ~IVParamObj() {}
|
virtual ~IVParamObj() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class TObjOwnerParam : public IVParamObj
|
||||||
|
{
|
||||||
|
T m_param;
|
||||||
|
public:
|
||||||
|
TObjOwnerParam(T&& obj) : m_param(std::move(obj)) {}
|
||||||
|
T& GetParam() {return m_param;}
|
||||||
|
};
|
||||||
|
|
||||||
class CVParamTransfer
|
class CVParamTransfer
|
||||||
{
|
{
|
||||||
std::shared_ptr<IVParamObj> m_ref;
|
std::shared_ptr<IVParamObj> m_ref;
|
||||||
|
@ -23,16 +32,10 @@ public:
|
||||||
IVParamObj* GetObj() const {return m_ref.get();}
|
IVParamObj* GetObj() const {return m_ref.get();}
|
||||||
CVParamTransfer ShareTransferRef() {return CVParamTransfer(*this);}
|
CVParamTransfer ShareTransferRef() {return CVParamTransfer(*this);}
|
||||||
|
|
||||||
static CVParamTransfer Null() {return CVParamTransfer();}
|
template <class T>
|
||||||
};
|
T& GetOwnedObj() const {return static_cast<TObjOwnerParam<T>*>(GetObj())->GetParam();}
|
||||||
|
|
||||||
template<class T>
|
static CVParamTransfer Null() {return CVParamTransfer();}
|
||||||
class TObjOwnerParam : public IVParamObj
|
|
||||||
{
|
|
||||||
T m_param;
|
|
||||||
public:
|
|
||||||
TObjOwnerParam(T&& obj) : m_param(std::move(obj)) {}
|
|
||||||
T& GetParam() {return m_param;}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,21 @@ namespace urde
|
||||||
namespace MP1
|
namespace MP1
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static const char* SaveFileNames[] =
|
||||||
|
{
|
||||||
|
"MetroidPrime A",
|
||||||
|
"MetroidPrime B"
|
||||||
|
};
|
||||||
|
|
||||||
using ECardResult = CMemoryCardSys::ECardResult;
|
using ECardResult = CMemoryCardSys::ECardResult;
|
||||||
using EMemoryCardPort = CMemoryCardSys::EMemoryCardPort;
|
using EMemoryCardPort = CMemoryCardSys::EMemoryCardPort;
|
||||||
|
|
||||||
|
ECardResult CMemoryCardDriver::SFileInfo::Open()
|
||||||
|
{
|
||||||
|
//CARDOpen(GetFileCardPort(), x14_name.data(), &x0_fileInfo);
|
||||||
|
return ECardResult::CARD_RESULT_READY;
|
||||||
|
}
|
||||||
|
|
||||||
ECardResult CMemoryCardDriver::SFileInfo::Close()
|
ECardResult CMemoryCardDriver::SFileInfo::Close()
|
||||||
{
|
{
|
||||||
auto backup = GetFileCardPort();
|
auto backup = GetFileCardPort();
|
||||||
|
@ -19,6 +31,20 @@ ECardResult CMemoryCardDriver::SFileInfo::Close()
|
||||||
return result;
|
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 CMemoryCardDriver::SFileInfo::TryFileRead()
|
||||||
{
|
{
|
||||||
ECardResult res = CMemoryCardSys::GetResultCode(GetFileCardPort());
|
ECardResult res = CMemoryCardSys::GetResultCode(GetFileCardPort());
|
||||||
|
@ -124,13 +150,13 @@ CMemoryCardDriver::SFileInfo::SFileInfo(EMemoryCardPort port,
|
||||||
}
|
}
|
||||||
|
|
||||||
CMemoryCardDriver::CMemoryCardDriver(EMemoryCardPort cardPort, ResId saveBanner,
|
CMemoryCardDriver::CMemoryCardDriver(EMemoryCardPort cardPort, ResId saveBanner,
|
||||||
ResId saveIcon0, ResId saveIcon1, bool mergePersistent)
|
ResId saveIcon0, ResId saveIcon1, bool importPersistent)
|
||||||
: x0_cardPort(cardPort), x4_saveBanner(saveBanner),
|
: 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.reserve(2);
|
||||||
x100_mcFileInfos.emplace_back(0, SFileInfo(x0_cardPort, "MetroidPrime A"));
|
x100_mcFileInfos.emplace_back(0, SFileInfo(x0_cardPort, SaveFileNames[0]));
|
||||||
x100_mcFileInfos.emplace_back(0, SFileInfo(x0_cardPort, "MetroidPrime B"));
|
x100_mcFileInfos.emplace_back(0, SFileInfo(x0_cardPort, SaveFileNames[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMemoryCardDriver::FinishedLoading()
|
void CMemoryCardDriver::FinishedLoading()
|
||||||
|
@ -152,7 +178,7 @@ void CMemoryCardDriver::FinishedLoading2()
|
||||||
x14_error = EError::Seven;
|
x14_error = EError::Seven;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
x10_state = EState::Five;
|
x10_state = EState::CardNeedsMount;
|
||||||
MountCard();
|
MountCard();
|
||||||
break;
|
break;
|
||||||
case ECardResult::CARD_RESULT_BUSY:
|
case ECardResult::CARD_RESULT_BUSY:
|
||||||
|
@ -169,13 +195,13 @@ void CMemoryCardDriver::FinishedLoading2()
|
||||||
|
|
||||||
void CMemoryCardDriver::NoCardFound()
|
void CMemoryCardDriver::NoCardFound()
|
||||||
{
|
{
|
||||||
x10_state = EState::Two;
|
x10_state = EState::NoCard;
|
||||||
static_cast<CMain*>(g_Main)->SetCardInserted(false);
|
static_cast<CMain*>(g_Main)->SetCardInserted(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMemoryCardDriver::MountCard()
|
void CMemoryCardDriver::MountCard()
|
||||||
{
|
{
|
||||||
x10_state = EState::TwentySix;
|
x10_state = EState::CardMount;
|
||||||
x14_error = EError::Zero;
|
x14_error = EError::Zero;
|
||||||
ECardResult result = CMemoryCardSys::MountCard(x0_cardPort);
|
ECardResult result = CMemoryCardSys::MountCard(x0_cardPort);
|
||||||
if (result != ECardResult::CARD_RESULT_READY)
|
if (result != ECardResult::CARD_RESULT_READY)
|
||||||
|
@ -229,22 +255,31 @@ void CMemoryCardDriver::ReadFinished()
|
||||||
for (int i=0 ; i<3 ; ++i)
|
for (int i=0 ; i<3 ; ++i)
|
||||||
xe4_fileSlots[i] = LoadSaveFile(r);
|
xe4_fileSlots[i] = LoadSaveFile(r);
|
||||||
|
|
||||||
if (x19d_doMergePersistent)
|
if (x19d_doImportPersistent)
|
||||||
MergePersistentOptions();
|
ImportPersistentOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMemoryCardDriver::MergePersistentOptions()
|
void CMemoryCardDriver::ImportPersistentOptions()
|
||||||
{
|
{
|
||||||
CBitStreamReader r(x30_systemData, 174);
|
CBitStreamReader r(x30_systemData, 174);
|
||||||
CPersistentOptions opts(r);
|
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()
|
void CMemoryCardDriver::DeleteFile()
|
||||||
{
|
{
|
||||||
x14_error = EError::Zero;
|
x14_error = EError::Zero;
|
||||||
x10_state = EState::Thirty;
|
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());
|
ECardResult result = CMemoryCardSys::FastDeleteFile(x0_cardPort, fileInfo.GetFileNo());
|
||||||
if (result != ECardResult::CARD_RESULT_READY)
|
if (result != ECardResult::CARD_RESULT_READY)
|
||||||
Case30(result);
|
Case30(result);
|
||||||
|
@ -261,11 +296,11 @@ void CMemoryCardDriver::Case26(ECardResult result)
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case ECardResult::CARD_RESULT_READY:
|
case ECardResult::CARD_RESULT_READY:
|
||||||
x10_state = EState::Six;
|
x10_state = EState::CardMountDone;
|
||||||
CheckCard();
|
CheckCard();
|
||||||
break;
|
break;
|
||||||
case ECardResult::CARD_RESULT_BROKEN:
|
case ECardResult::CARD_RESULT_BROKEN:
|
||||||
x10_state = EState::Six;
|
x10_state = EState::CardMountDone;
|
||||||
x14_error = EError::One;
|
x14_error = EError::One;
|
||||||
CheckCard();
|
CheckCard();
|
||||||
break;
|
break;
|
||||||
|
@ -280,7 +315,7 @@ void CMemoryCardDriver::Case27(ECardResult result)
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case ECardResult::CARD_RESULT_READY:
|
case ECardResult::CARD_RESULT_READY:
|
||||||
x10_state = EState::Seven;
|
x10_state = EState::SelectCardFile;
|
||||||
if (!GetCardFreeBytes())
|
if (!GetCardFreeBytes())
|
||||||
return;
|
return;
|
||||||
if (CMemoryCardSys::GetSerialNo(x0_cardPort, x28_cardSerial) == ECardResult::CARD_RESULT_READY)
|
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)
|
if (result == ECardResult::CARD_RESULT_READY)
|
||||||
{
|
{
|
||||||
x100_mcFileInfos[x194_fileIdx].first = 1;
|
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;
|
x10_state = EState::Seventeen;
|
||||||
GoTo28();
|
GoTo28();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
x10_state = EState::Seven;
|
x10_state = EState::SelectCardFile;
|
||||||
if (!GetCardFreeBytes())
|
if (!GetCardFreeBytes())
|
||||||
return;
|
return;
|
||||||
GoTo17();
|
GoTo17();
|
||||||
|
@ -330,10 +365,10 @@ void CMemoryCardDriver::Case29(ECardResult result)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fileIdx = bool(x194_fileIdx);
|
u32 fileIdx = !bool(x194_fileIdx);
|
||||||
if (readRes == ECardResult::CARD_RESULT_READY)
|
if (readRes == ECardResult::CARD_RESULT_READY)
|
||||||
{
|
{
|
||||||
x10_state = EState::One;
|
x10_state = EState::Ready;
|
||||||
ReadFinished();
|
ReadFinished();
|
||||||
u32 fileId = x100_mcFileInfos[fileIdx].first;
|
u32 fileId = x100_mcFileInfos[fileIdx].first;
|
||||||
if (fileId == 1)
|
if (fileId == 1)
|
||||||
|
@ -348,7 +383,7 @@ void CMemoryCardDriver::Case29(ECardResult result)
|
||||||
x100_mcFileInfos[x194_fileIdx].first = 3;
|
x100_mcFileInfos[x194_fileIdx].first = 3;
|
||||||
if (x100_mcFileInfos[fileIdx].first == 2)
|
if (x100_mcFileInfos[fileIdx].first == 2)
|
||||||
{
|
{
|
||||||
x10_state = EState::Seven;
|
x10_state = EState::SelectCardFile;
|
||||||
GoTo17();
|
GoTo17();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -364,52 +399,347 @@ void CMemoryCardDriver::Case29(ECardResult result)
|
||||||
|
|
||||||
void CMemoryCardDriver::Case30(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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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()
|
void CMemoryCardDriver::GoTo17()
|
||||||
{
|
{
|
||||||
|
x14_error = EError::Zero;
|
||||||
|
for (std::pair<u32, SFileInfo>& 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()
|
void CMemoryCardDriver::GoTo28()
|
||||||
{
|
{
|
||||||
|
x14_error = EError::Zero;
|
||||||
|
x10_state = EState::TwentyEight;
|
||||||
|
int idx = 0;
|
||||||
|
for (std::pair<u32, SFileInfo>& 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<CMemoryCardSys::CCardFileInfo>(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()
|
bool CMemoryCardDriver::GetCardFreeBytes()
|
||||||
|
@ -451,7 +781,7 @@ void CMemoryCardDriver::Update()
|
||||||
|
|
||||||
if (result.x0_error == ECardResult::CARD_RESULT_NOCARD)
|
if (result.x0_error == ECardResult::CARD_RESULT_NOCARD)
|
||||||
{
|
{
|
||||||
if (x10_state != EState::Two)
|
if (x10_state != EState::NoCard)
|
||||||
NoCardFound();
|
NoCardFound();
|
||||||
static_cast<CMain*>(g_Main)->SetCardInserted(false);
|
static_cast<CMain*>(g_Main)->SetCardInserted(false);
|
||||||
return;
|
return;
|
||||||
|
@ -474,7 +804,7 @@ void CMemoryCardDriver::Update()
|
||||||
|
|
||||||
switch (x10_state)
|
switch (x10_state)
|
||||||
{
|
{
|
||||||
case EState::TwentySix:
|
case EState::CardMount:
|
||||||
Case26(resultCode);
|
Case26(resultCode);
|
||||||
break;
|
break;
|
||||||
case EState::TwentySeven:
|
case EState::TwentySeven:
|
||||||
|
@ -492,7 +822,7 @@ void CMemoryCardDriver::Update()
|
||||||
case EState::ThirtyOne:
|
case EState::ThirtyOne:
|
||||||
Case31(resultCode);
|
Case31(resultCode);
|
||||||
break;
|
break;
|
||||||
case EState::ThirtyTwo:
|
case EState::Write:
|
||||||
Case32(resultCode);
|
Case32(resultCode);
|
||||||
break;
|
break;
|
||||||
case EState::ThirtyThree:
|
case EState::ThirtyThree:
|
||||||
|
@ -507,7 +837,7 @@ void CMemoryCardDriver::Update()
|
||||||
case EState::ThirtySix:
|
case EState::ThirtySix:
|
||||||
Case36(resultCode);
|
Case36(resultCode);
|
||||||
break;
|
break;
|
||||||
case EState::ThirtySeven:
|
case EState::CardFormat:
|
||||||
Case37(resultCode);
|
Case37(resultCode);
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
|
|
|
@ -15,30 +15,44 @@ class CMemoryCardDriver
|
||||||
public:
|
public:
|
||||||
enum class EState
|
enum class EState
|
||||||
{
|
{
|
||||||
Zero,
|
Initial,
|
||||||
One = 1,
|
Ready = 1,
|
||||||
Two = 2,
|
NoCard = 2,
|
||||||
Five = 5,
|
RuntimeBackup = 3,
|
||||||
Six = 6,
|
CardFormatted = 4,
|
||||||
Seven = 7,
|
CardNeedsMount = 5,
|
||||||
|
CardMountDone = 6,
|
||||||
|
SelectCardFile = 7,
|
||||||
|
WillWrite = 8,
|
||||||
|
Nine = 9,
|
||||||
|
Ten = 10,
|
||||||
|
Eleven = 11,
|
||||||
Twelve = 12,
|
Twelve = 12,
|
||||||
Thirteen = 13,
|
Thirteen = 13,
|
||||||
Fourteen = 14,
|
Fourteen = 14,
|
||||||
Fifteen = 15,
|
Fifteen = 15,
|
||||||
|
Sixteen = 16,
|
||||||
Seventeen = 17,
|
Seventeen = 17,
|
||||||
TwentyFive = 26,
|
Eighteen = 18,
|
||||||
TwentySix = 26,
|
Nineteen = 19,
|
||||||
|
Twenty = 20,
|
||||||
|
TwentyOne = 21,
|
||||||
|
TwentyTwo = 22,
|
||||||
|
TwentyThree = 23,
|
||||||
|
CardFormatBroken = 24,
|
||||||
|
TwentyFive = 25,
|
||||||
|
CardMount = 26,
|
||||||
TwentySeven = 27,
|
TwentySeven = 27,
|
||||||
TwentyEight = 28,
|
TwentyEight = 28,
|
||||||
TwentyNine = 29,
|
TwentyNine = 29,
|
||||||
Thirty = 30,
|
Thirty = 30,
|
||||||
ThirtyOne = 31,
|
ThirtyOne = 31,
|
||||||
ThirtyTwo = 32,
|
Write = 32,
|
||||||
ThirtyThree = 33,
|
ThirtyThree = 33,
|
||||||
ThirtyFour = 34,
|
ThirtyFour = 34,
|
||||||
ThirtyFive = 35,
|
ThirtyFive = 35,
|
||||||
ThirtySix = 36,
|
ThirtySix = 36,
|
||||||
ThirtySeven = 37
|
CardFormat = 37
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EError
|
enum class EError
|
||||||
|
@ -72,9 +86,11 @@ private:
|
||||||
std::vector<u8> x24_saveFileData;
|
std::vector<u8> x24_saveFileData;
|
||||||
std::vector<u8> x34_saveData;
|
std::vector<u8> x34_saveData;
|
||||||
SFileInfo(CMemoryCardSys::EMemoryCardPort cardPort, const std::string& name);
|
SFileInfo(CMemoryCardSys::EMemoryCardPort cardPort, const std::string& name);
|
||||||
|
CMemoryCardSys::ECardResult Open();
|
||||||
CMemoryCardSys::ECardResult Close();
|
CMemoryCardSys::ECardResult Close();
|
||||||
CMemoryCardSys::EMemoryCardPort GetFileCardPort() const { return x0_fileInfo.x0_cardPort; }
|
CMemoryCardSys::EMemoryCardPort GetFileCardPort() const { return x0_fileInfo.x0_cardPort; }
|
||||||
int GetFileNo() const { return x0_fileInfo.x4_fileNo; }
|
int GetFileNo() const { return x0_fileInfo.x4_fileNo; }
|
||||||
|
CMemoryCardSys::ECardResult StartRead();
|
||||||
CMemoryCardSys::ECardResult TryFileRead();
|
CMemoryCardSys::ECardResult TryFileRead();
|
||||||
CMemoryCardSys::ECardResult FileRead();
|
CMemoryCardSys::ECardResult FileRead();
|
||||||
CMemoryCardSys::ECardResult GetSaveDataOffset(u32& offOut);
|
CMemoryCardSys::ECardResult GetSaveDataOffset(u32& offOut);
|
||||||
|
@ -99,7 +115,7 @@ private:
|
||||||
ResId x4_saveBanner;
|
ResId x4_saveBanner;
|
||||||
ResId x8_saveIcon0;
|
ResId x8_saveIcon0;
|
||||||
ResId xc_saveIcon1;
|
ResId xc_saveIcon1;
|
||||||
EState x10_state = EState::Zero;
|
EState x10_state = EState::Initial;
|
||||||
EError x14_error = EError::Zero;
|
EError x14_error = EError::Zero;
|
||||||
s32 x18_cardFreeBytes = 0;
|
s32 x18_cardFreeBytes = 0;
|
||||||
s32 x1c_cardFreeFiles = 0;
|
s32 x1c_cardFreeFiles = 0;
|
||||||
|
@ -110,13 +126,13 @@ private:
|
||||||
std::unique_ptr<SGameFileSlot> xe4_fileSlots[3];
|
std::unique_ptr<SGameFileSlot> xe4_fileSlots[3];
|
||||||
std::vector<std::pair<u32, SFileInfo>> x100_mcFileInfos;
|
std::vector<std::pair<u32, SFileInfo>> x100_mcFileInfos;
|
||||||
u32 x194_fileIdx = -1;
|
u32 x194_fileIdx = -1;
|
||||||
u32 x198_ = 0;
|
std::unique_ptr<CMemoryCardSys::CCardFileInfo> x198_fileInfo;
|
||||||
bool x19c_ = false;
|
bool x19c_ = false;
|
||||||
bool x19d_doMergePersistent;
|
bool x19d_doImportPersistent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMemoryCardDriver(CMemoryCardSys::EMemoryCardPort cardPort, ResId saveBanner,
|
CMemoryCardDriver(CMemoryCardSys::EMemoryCardPort cardPort, ResId saveBanner,
|
||||||
ResId saveIcon0, ResId saveIcon1, bool flag);
|
ResId saveIcon0, ResId saveIcon1, bool importPersistent);
|
||||||
void FinishedLoading();
|
void FinishedLoading();
|
||||||
void FinishedLoading2();
|
void FinishedLoading2();
|
||||||
void NoCardFound();
|
void NoCardFound();
|
||||||
|
@ -127,7 +143,8 @@ public:
|
||||||
static SSaveHeader LoadSaveHeader(CMemoryInStream& in);
|
static SSaveHeader LoadSaveHeader(CMemoryInStream& in);
|
||||||
static std::unique_ptr<SGameFileSlot> LoadSaveFile(CMemoryInStream& in);
|
static std::unique_ptr<SGameFileSlot> LoadSaveFile(CMemoryInStream& in);
|
||||||
void ReadFinished();
|
void ReadFinished();
|
||||||
void MergePersistentOptions();
|
void ImportPersistentOptions();
|
||||||
|
void ExportPersistentOptions();
|
||||||
void DeleteFile();
|
void DeleteFile();
|
||||||
void CheckCardCapacity();
|
void CheckCardCapacity();
|
||||||
|
|
||||||
|
@ -146,14 +163,24 @@ public:
|
||||||
|
|
||||||
void GoTo17();
|
void GoTo17();
|
||||||
void GoTo28();
|
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();
|
bool GetCardFreeBytes();
|
||||||
void HandleCardError(CMemoryCardSys::ECardResult result, EState state);
|
void HandleCardError(CMemoryCardSys::ECardResult result, EState state);
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
static bool InCardInsertedRange(EState v)
|
static bool InCardInsertedRange(EState v)
|
||||||
{
|
{
|
||||||
return v >= EState::TwentySix && v <= EState::ThirtySeven;
|
return v >= EState::CardMount && v <= EState::CardFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool InRange2(EState v)
|
static bool InRange2(EState v)
|
||||||
|
|
|
@ -59,7 +59,7 @@ bool CSaveUI::PumpLoad()
|
||||||
|
|
||||||
CSaveUI::UIType CSaveUI::SelectUIType() const
|
CSaveUI::UIType CSaveUI::SelectUIType() const
|
||||||
{
|
{
|
||||||
if (x6c_cardDriver->x10_state == EState::Two)
|
if (x6c_cardDriver->x10_state == EState::NoCard)
|
||||||
return UIType::Three;
|
return UIType::Three;
|
||||||
|
|
||||||
switch (x10_uiType)
|
switch (x10_uiType)
|
||||||
|
@ -78,7 +78,7 @@ CSaveUI::UIType CSaveUI::SelectUIType() const
|
||||||
return UIType::One;
|
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)
|
if (x6c_cardDriver->x14_error == CMemoryCardDriver::EError::Six)
|
||||||
return UIType::Twelve;
|
return UIType::Twelve;
|
||||||
|
|
|
@ -139,7 +139,7 @@ void CDecalDataFactory::GetQuadDecalInfo(CInputStream& in, CSimplePool* resPool,
|
||||||
|
|
||||||
CFactoryFnReturn FDecalDataFactory(const SObjectTag &tag, CInputStream &in, const CVParamTransfer &vparms)
|
CFactoryFnReturn FDecalDataFactory(const SObjectTag &tag, CInputStream &in, const CVParamTransfer &vparms)
|
||||||
{
|
{
|
||||||
CSimplePool* sp = static_cast<CSimplePool*>(static_cast<TObjOwnerParam<IObjectStore*>*>(vparms.GetObj())->GetParam());
|
CSimplePool* sp = vparms.GetOwnedObj<CSimplePool*>();
|
||||||
return TToken<CDecalDescription>::GetIObjObjectFor(std::unique_ptr<CDecalDescription>(CDecalDataFactory::GetGeneratorDesc(in, sp)));
|
return TToken<CDecalDescription>::GetIObjObjectFor(std::unique_ptr<CDecalDescription>(CDecalDataFactory::GetGeneratorDesc(in, sp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1160,7 +1160,7 @@ CFactoryFnReturn FParticleFactory(const SObjectTag& tag, CInputStream& in,
|
||||||
const CVParamTransfer& vparms,
|
const CVParamTransfer& vparms,
|
||||||
CObjectReference* selfRef)
|
CObjectReference* selfRef)
|
||||||
{
|
{
|
||||||
CSimplePool* sp = static_cast<CSimplePool*>(static_cast<TObjOwnerParam<IObjectStore*>*>(vparms.GetObj())->GetParam());
|
CSimplePool* sp = vparms.GetOwnedObj<CSimplePool*>();
|
||||||
return TToken<CGenDescription>::GetIObjObjectFor(std::unique_ptr<CGenDescription>(CParticleDataFactory::GetGeneratorDesc(in, sp)));
|
return TToken<CGenDescription>::GetIObjObjectFor(std::unique_ptr<CGenDescription>(CParticleDataFactory::GetGeneratorDesc(in, sp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ void CParticleElectricDataFactory::LoadELSMTokens(CElectricDescription* desc)
|
||||||
|
|
||||||
CFactoryFnReturn FParticleElectricDataFactory(const SObjectTag &tag, CInputStream &in, const CVParamTransfer &vparms)
|
CFactoryFnReturn FParticleElectricDataFactory(const SObjectTag &tag, CInputStream &in, const CVParamTransfer &vparms)
|
||||||
{
|
{
|
||||||
CSimplePool* sp = static_cast<CSimplePool*>(static_cast<TObjOwnerParam<IObjectStore*>*>(vparms.GetObj())->GetParam());
|
CSimplePool* sp = vparms.GetOwnedObj<CSimplePool*>();
|
||||||
return TToken<CElectricDescription>::GetIObjObjectFor(std::unique_ptr<CElectricDescription>(CParticleElectricDataFactory::GetGeneratorDesc(in, sp)));
|
return TToken<CElectricDescription>::GetIObjObjectFor(std::unique_ptr<CElectricDescription>(CParticleElectricDataFactory::GetGeneratorDesc(in, sp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@ bool CParticleSwooshDataFactory::CreateWPSM(CSwooshDescription* desc, CInputStre
|
||||||
|
|
||||||
CFactoryFnReturn FParticleSwooshDataFactory(const SObjectTag &tag, CInputStream &in, const CVParamTransfer &vparms)
|
CFactoryFnReturn FParticleSwooshDataFactory(const SObjectTag &tag, CInputStream &in, const CVParamTransfer &vparms)
|
||||||
{
|
{
|
||||||
CSimplePool* sp = static_cast<CSimplePool*>(static_cast<TObjOwnerParam<IObjectStore*>*>(vparms.GetObj())->GetParam());
|
CSimplePool* sp = vparms.GetOwnedObj<CSimplePool*>();
|
||||||
return TToken<CSwooshDescription>::GetIObjObjectFor(std::unique_ptr<CSwooshDescription>(CParticleSwooshDataFactory::GetGeneratorDesc(in, sp)));
|
return TToken<CSwooshDescription>::GetIObjObjectFor(std::unique_ptr<CSwooshDescription>(CParticleSwooshDataFactory::GetGeneratorDesc(in, sp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ bool CProjectileWeaponDataFactory::CreateWPSM(CWeaponDescription* desc, CInputSt
|
||||||
|
|
||||||
CFactoryFnReturn FProjectileWeaponDataFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms)
|
CFactoryFnReturn FProjectileWeaponDataFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms)
|
||||||
{
|
{
|
||||||
CSimplePool* sp = static_cast<CSimplePool*>(static_cast<TObjOwnerParam<IObjectStore*>*>(vparms.GetObj())->GetParam());
|
CSimplePool* sp = vparms.GetOwnedObj<CSimplePool*>();
|
||||||
return TToken<CWeaponDescription>::GetIObjObjectFor(std::unique_ptr<CWeaponDescription>(CProjectileWeaponDataFactory::GetGeneratorDesc(in, sp)));
|
return TToken<CWeaponDescription>::GetIObjObjectFor(std::unique_ptr<CWeaponDescription>(CProjectileWeaponDataFactory::GetGeneratorDesc(in, sp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue