diff --git a/Runtime/AutoMapper/CMapWorldInfo.cpp b/Runtime/AutoMapper/CMapWorldInfo.cpp index 14b963d37..3f5ed0c3e 100644 --- a/Runtime/AutoMapper/CMapWorldInfo.cpp +++ b/Runtime/AutoMapper/CMapWorldInfo.cpp @@ -19,6 +19,11 @@ CMapWorldInfo::CMapWorldInfo(CBitStreamReader& reader, const CSaveWorld& saveWor } +void CMapWorldInfo::PutTo(CBitStreamWriter& writer, const CSaveWorld& savw) const +{ + +} + void CMapWorldInfo::SetDoorVisited(TEditorId eid, bool visited) { x14_[eid] = visited; diff --git a/Runtime/AutoMapper/CMapWorldInfo.hpp b/Runtime/AutoMapper/CMapWorldInfo.hpp index 3442b5514..16b4dee7e 100644 --- a/Runtime/AutoMapper/CMapWorldInfo.hpp +++ b/Runtime/AutoMapper/CMapWorldInfo.hpp @@ -15,7 +15,7 @@ class CMapWorldInfo public: CMapWorldInfo()=default; CMapWorldInfo(CBitStreamReader&, const CSaveWorld& saveWorld, ResId mlvlId); - void PutTo(COutputStream&); + void PutTo(CBitStreamWriter& writer, const CSaveWorld& savw) const; bool IsMapped() const; void SetIsMapped(bool) const; void SetDoorVisited(TEditorId eid, bool val); diff --git a/Runtime/CBasics.hpp b/Runtime/CBasics.hpp index 673e0d9b0..02007dd8f 100644 --- a/Runtime/CBasics.hpp +++ b/Runtime/CBasics.hpp @@ -3,17 +3,26 @@ #include #include +#include #include "RetroTypes.hpp" namespace urde { +using OSTime = s64; + class CBasics { public: static void Init(); static const char* Stringize(const char* fmt, ...); + + static const u64 SECONDS_TO_2000; + static const u64 TICKS_PER_SECOND; + + static OSTime ToWiiTime(std::chrono::system_clock::time_point time); + static std::chrono::system_clock::time_point FromWiiTime(OSTime wiiTime); }; } diff --git a/Runtime/CBasicsPC.cpp b/Runtime/CBasicsPC.cpp index 521debcbf..c7127df94 100644 --- a/Runtime/CBasicsPC.cpp +++ b/Runtime/CBasicsPC.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "CBasics.hpp" @@ -20,4 +21,42 @@ const char* CBasics::Stringize(const char* fmt, ...) return STRINGIZE_STR; } +const u64 CBasics::SECONDS_TO_2000 = 946684800LL; +const u64 CBasics::TICKS_PER_SECOND = 60750000LL; + +OSTime CBasics::ToWiiTime(std::chrono::system_clock::time_point time) +{ + time_t sysTime, tzDiff; + struct tm* gmTime; + + sysTime = std::chrono::system_clock::to_time_t(time); + // Account for DST where needed + gmTime = localtime(&sysTime); + if (!gmTime) + return 0; + + // Lazy way to get local time in sec + gmTime = gmtime(&sysTime); + tzDiff = sysTime - mktime(gmTime); + + return OSTime(TICKS_PER_SECOND * ((sysTime + tzDiff) - SECONDS_TO_2000)); +} + +std::chrono::system_clock::time_point CBasics::FromWiiTime(OSTime wiiTime) +{ + time_t time = SECONDS_TO_2000 + wiiTime / TICKS_PER_SECOND; + + time_t sysTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + // Account for DST where needed + struct tm* gmTime = localtime(&sysTime); + if (!gmTime) + return std::chrono::system_clock::from_time_t(0); + + // Lazy way to get local time in sec + gmTime = gmtime(&sysTime); + time_t tzDiff = sysTime - mktime(gmTime); + + return std::chrono::system_clock::from_time_t(time - tzDiff); +} + } diff --git a/Runtime/CGameOptions.cpp b/Runtime/CGameOptions.cpp index af1b04904..11c637965 100644 --- a/Runtime/CGameOptions.cpp +++ b/Runtime/CGameOptions.cpp @@ -91,6 +91,29 @@ CGameOptions::CGameOptions(CBitStreamReader& stream) x68_27_ = stream.ReadEncoded(1); } +void CGameOptions::PutTo(CBitStreamWriter& writer) const +{ + for (int b=0 ; b<64 ; ++b) + writer.WriteEncoded(x0_[b], 1); + + writer.WriteEncoded(u32(x44_soundMode), 2); + writer.WriteEncoded(x48_, 4); + + writer.WriteEncoded(x4c_, 6); + writer.WriteEncoded(x50_, 6); + writer.WriteEncoded(x54_, 5); + writer.WriteEncoded(x58_, 7); + writer.WriteEncoded(x5c_, 7); + writer.WriteEncoded(x60_, 8); + writer.WriteEncoded(x64_, 8); + + writer.WriteEncoded(x68_24_, 1); + writer.WriteEncoded(x68_28_, 1); + writer.WriteEncoded(x68_25_, 1); + writer.WriteEncoded(x68_26_, 1); + writer.WriteEncoded(x68_27_, 1); +} + CGameOptions::CGameOptions() { x68_24_ = true; @@ -126,4 +149,13 @@ CHintOptions::CHintOptions(CBitStreamReader& stream) } } +void CHintOptions::PutTo(CBitStreamWriter& writer) const +{ + for (const SHintState& hint : x0_hintStates) + { + writer.WriteEncoded(u32(hint.x0_state), 2); + writer.WriteEncoded(reinterpret_cast(hint.x4_time), 32); + } +} + } diff --git a/Runtime/CGameOptions.hpp b/Runtime/CGameOptions.hpp index 696f98f32..be2eae24b 100644 --- a/Runtime/CGameOptions.hpp +++ b/Runtime/CGameOptions.hpp @@ -86,6 +86,7 @@ public: CGameOptions(); CGameOptions(CBitStreamReader& stream); void InitSoundMode(); + void PutTo(CBitStreamWriter& writer) const; }; class CHintOptions @@ -113,6 +114,7 @@ private: public: CHintOptions() = default; CHintOptions(CBitStreamReader& stream); + void PutTo(CBitStreamWriter& writer) const; }; } diff --git a/Runtime/CGameState.cpp b/Runtime/CGameState.cpp index 1726ea77e..4ddda5024 100644 --- a/Runtime/CGameState.cpp +++ b/Runtime/CGameState.cpp @@ -24,6 +24,22 @@ CWorldLayerState::CWorldLayerState(CBitStreamReader& reader, const CSaveWorld& s } } +void CWorldLayerState::PutTo(CBitStreamWriter& writer) const +{ + u32 totalLayerCount = 0; + for (int i=0 ; i& layers) { if (x0_areaLayers.size()) @@ -63,6 +79,15 @@ CWorldState::CWorldState(CBitStreamReader& reader, ResId mlvlId, const CSaveWorl x14_layerState = std::make_shared(reader, saveWorld); } +void CWorldState::PutTo(CBitStreamWriter& writer, const CSaveWorld& savw) const +{ + writer.WriteEncoded(x4_areaId, 32); + writer.WriteEncoded(x10_, 32); + x8_relayTracker->PutTo(writer, savw); + xc_mapWorldInfo->PutTo(writer, savw); + x14_layerState->PutTo(writer); +} + CGameState::CGameState() { x98_playerState.reset(new CPlayerState()); @@ -75,17 +100,26 @@ CGameState::CGameState(CBitStreamReader& stream) x228_25_deferPowerupInit = true; for (u32 i = 0; i < 128; i++) - stream.ReadEncoded(8); - u32 tmp = stream.ReadEncoded(32); - float val1 = reinterpret_cast(tmp); - bool val2 = stream.ReadEncoded(1); - stream.ReadEncoded(1); - tmp = stream.ReadEncoded(32); - float val3 = reinterpret_cast(tmp); - tmp = stream.ReadEncoded(32); - float val4 = reinterpret_cast(tmp); - tmp = stream.ReadEncoded(32); - float val5 = reinterpret_cast(tmp); + x0_[i] = stream.ReadEncoded(8); + u32 tsSeconds = stream.ReadEncoded(32); + + x228_24_ = stream.ReadEncoded(1); + x228_25_deferPowerupInit = stream.ReadEncoded(1); + x84_mlvlId = stream.ReadEncoded(32); + EnsureWorldPakReady(x84_mlvlId); + + union BitsToDouble + { + struct + { + u32 low; + u32 high; + }; + double doub; + } conv; + conv.low = stream.ReadEncoded(32); + conv.high = stream.ReadEncoded(32); + xa0_playTime = conv.doub; x98_playerState = std::make_shared(stream); float currentHealth = x98_playerState->GetHealthInfo().GetHP(); @@ -103,8 +137,54 @@ CGameState::CGameState(CBitStreamReader& stream) } } -void CGameState::SetCurrentWorldId(unsigned int id) + +void CGameState::PutTo(CBitStreamWriter& writer) const { + for (u32 i = 0; i < 128; i++) + writer.WriteEncoded(x0_[i], 8); + + writer.WriteEncoded(CBasics::ToWiiTime(std::chrono::system_clock::now()) / CBasics::TICKS_PER_SECOND, 32); + writer.WriteEncoded(x228_24_, 1); + writer.WriteEncoded(x228_25_deferPowerupInit, 1); + writer.WriteEncoded(x84_mlvlId, 32); + + union BitsToDouble + { + struct + { + u32 low; + u32 high; + }; + double doub; + } conv; + conv.doub = xa0_playTime; + writer.WriteEncoded(conv.low, 32); + writer.WriteEncoded(conv.high, 32); + + x98_playerState->PutTo(writer); + x17c_gameOptions.PutTo(writer); + x1f8_hintOptions.PutTo(writer); + + const auto& memWorlds = g_MemoryCardSys->GetMemoryWorlds(); + for (const auto& memWorld : memWorlds) + { + TLockedToken saveWorld = + g_SimplePool->GetObj(SObjectTag{FOURCC('SAVW'), memWorld.second.GetSaveWorldAssetId()}); + const CWorldState& wld = const_cast(*this).StateForWorld(memWorld.first); + wld.PutTo(writer, *saveWorld); + } +} + +void CGameState::EnsureWorldPakReady(ResId mlvl) +{ + /* TODO: Schedule resource list load for World Pak containing mlvl */ +} + +void CGameState::SetCurrentWorldId(ResId id) +{ + StateForWorld(id); + x84_mlvlId = id; + EnsureWorldPakReady(x84_mlvlId); } void CGameState::SetTotalPlayTime(float time) diff --git a/Runtime/CGameState.hpp b/Runtime/CGameState.hpp index 545238f49..5655a902e 100644 --- a/Runtime/CGameState.hpp +++ b/Runtime/CGameState.hpp @@ -38,6 +38,13 @@ public: } void InitializeWorldLayers(const std::vector& layers); + + u32 GetAreaLayerCount(int areaIdx) const + { + return x0_areaLayers[areaIdx].m_layerCount; + } + + void PutTo(CBitStreamWriter& writer) const; }; class CWorldState @@ -57,6 +64,7 @@ public: const std::shared_ptr& RelayTracker() const { return x8_relayTracker; } const std::shared_ptr& MapWorldInfo() const { return xc_mapWorldInfo; } const std::shared_ptr& GetLayerState() const { return x14_layerState; } + void PutTo(CBitStreamWriter& writer, const CSaveWorld& savw) const; }; class CGameState @@ -83,10 +91,12 @@ class CGameState u8 _dummy = 0; }; + static void EnsureWorldPakReady(ResId mlvl); + public: CGameState(); CGameState(CBitStreamReader& stream); - void SetCurrentWorldId(unsigned int id); + void SetCurrentWorldId(ResId id); std::shared_ptr GetPlayerState() {return x98_playerState;} std::shared_ptr GetWorldTransitionManager() {return x9c_transManager;} void SetTotalPlayTime(float time); @@ -95,6 +105,7 @@ public: CWorldState& StateForWorld(ResId mlvlId); CWorldState& CurrentWorldState() { return StateForWorld(x84_mlvlId); } ResId CurrentWorldAssetId() const { return x84_mlvlId; } + void PutTo(CBitStreamWriter& writer) const; }; } diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index 4923ad481..a61f14dc1 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -291,8 +291,6 @@ public: const std::shared_ptr& MapWorldInfo() const { return x8c0_mapWorldInfo; } const std::shared_ptr& LayerState() const { return x8c8_worldLayerState; } - bool IsLayerActive(TAreaId area, int layerIdx) { return false; } - CPlayer& GetPlayer() const { return *x84c_player; } CPlayer* Player() const { return x84c_player.get(); } diff --git a/Runtime/World/CGameArea.cpp b/Runtime/World/CGameArea.cpp index a8fbedeb7..a44054f84 100644 --- a/Runtime/World/CGameArea.cpp +++ b/Runtime/World/CGameArea.cpp @@ -4,6 +4,7 @@ #include "CSimplePool.hpp" #include "CStateManager.hpp" #include "World/CScriptAreaAttributes.hpp" +#include "CGameState.hpp" namespace urde { @@ -841,7 +842,7 @@ void CGameArea::VerifyTokenList(CStateManager& stateMgr) int lidx = 0; for (u32 off : xbc_layerDepOffsets) { - if (stateMgr.IsLayerActive(x4_selfIdx, lidx)) + if (stateMgr.LayerState()->IsLayerActive(x4_selfIdx, lidx)) { auto it = xac_deps2.begin() + lastOff; auto end = xac_deps2.begin() + off;