Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions UnleashedRecomp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ set(UNLEASHED_RECOMP_USER_CXX_SOURCES
"user/config.cpp"
"user/registry.cpp"
"user/paths.cpp"
"user/persistent_data.cpp"
"user/persistent_storage_manager.cpp"
)

set(UNLEASHED_RECOMP_MOD_CXX_SOURCES
Expand Down
10 changes: 8 additions & 2 deletions UnleashedRecomp/api/SWA/System/ApplicationDocument.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,13 @@ namespace SWA
boost::shared_ptr<Hedgehog::Mirage::CRenderScene> m_spRenderScene;
SWA_INSERT_PADDING(0x04);
boost::shared_ptr<CGameParameter> m_spGameParameter;
SWA_INSERT_PADDING(0x78);
SWA_INSERT_PADDING(0x0C);
boost::anonymous_shared_ptr m_spItemParamManager;
SWA_INSERT_PADDING(0x64);
boost::shared_ptr<Hedgehog::Base::CCriticalSection> m_spCriticalSection;
SWA_INSERT_PADDING(0x20);
SWA_INSERT_PADDING(0x14);
bool m_ShowDLCInfo;
SWA_INSERT_PADDING(0x08);
};

// TODO: Hedgehog::Base::TSynchronizedPtr<CApplicationDocument>
Expand Down Expand Up @@ -111,7 +115,9 @@ namespace SWA
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_Field10C, 0x10C);
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_spRenderScene, 0x12C);
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_spGameParameter, 0x138);
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_spItemParamManager, 0x14C);
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_spCriticalSection, 0x1B8);
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_ShowDLCInfo, 0x1D4);
SWA_ASSERT_SIZEOF(CApplicationDocument::CMember, 0x1E0);

SWA_ASSERT_OFFSETOF(CApplicationDocument, m_pMember, 0x04);
Expand Down
10 changes: 9 additions & 1 deletion UnleashedRecomp/api/SWA/System/GameParameter.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ namespace SWA
class CGameParameter // : public Hedgehog::Universe::CMessageActor
{
public:
struct SSaveData;
struct SSaveData
{
SWA_INSERT_PADDING(0x8600);
be<uint32_t> DLCFlags[8];
SWA_INSERT_PADDING(0x15C);
};

struct SStageParameter;

SWA_INSERT_PADDING(0x94);
xpointer<SSaveData> m_pSaveData;
xpointer<SStageParameter> m_pStageParameter;
};

SWA_ASSERT_OFFSETOF(CGameParameter::SSaveData, DLCFlags, 0x8600);
}
4 changes: 4 additions & 0 deletions UnleashedRecomp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <hid/hid.h>
#include <user/config.h>
#include <user/paths.h>
#include <user/persistent_storage_manager.h>
#include <user/registry.h>
#include <kernel/xdbf.h>
#include <install/installer.h>
Expand Down Expand Up @@ -212,6 +213,9 @@ int main(int argc, char *argv[])
}

Config::Load();

if (!PersistentStorageManager::LoadBinary())
LOGFN_ERROR("Failed to load persistent storage binary... (status code {})", (int)PersistentStorageManager::BinStatus);

#if defined(_WIN32) && defined(UNLEASHED_RECOMP_D3D12)
for (auto& dll : g_D3D12RequiredModules)
Expand Down
16 changes: 9 additions & 7 deletions UnleashedRecomp/patches/CTitleStateIntro_patches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <api/SWA.h>
#include <install/update_checker.h>
#include <locale/locale.h>
#include <os/logger.h>
#include <ui/fader.h>
#include <ui/message_window.h>
#include <user/achievement_manager.h>
Expand Down Expand Up @@ -64,16 +65,16 @@ static bool ProcessCorruptAchievementsMessage()
if (!g_corruptAchievementsMessageOpen)
return false;

auto message = AchievementManager::Status == EAchStatus::IOError
auto message = AchievementManager::BinStatus == EAchBinStatus::IOError
? Localise("Title_Message_AchievementDataIOError")
: Localise("Title_Message_AchievementDataCorrupt");

if (MessageWindow::Open(message, &g_corruptAchievementsMessageResult) == MSG_CLOSED)
{
// Allow user to proceed if the achievement data couldn't be loaded.
// Restarting may fix this error, so it isn't worth clearing the data for.
if (AchievementManager::Status != EAchStatus::IOError)
AchievementManager::Save(true);
// Create a new save file if the file was successfully loaded and failed validation.
// If the file couldn't be opened, restarting may fix this error, so it isn't worth clearing the data for.
if (AchievementManager::BinStatus != EAchBinStatus::IOError)
AchievementManager::SaveBinary(true);

g_corruptAchievementsMessageOpen = false;
g_corruptAchievementsMessageOpen.notify_one();
Expand Down Expand Up @@ -135,9 +136,10 @@ void PressStartSaveLoadThreadMidAsmHook()
g_faderBegun.wait(true);
}

AchievementManager::Load();
if (!AchievementManager::LoadBinary())
LOGFN_ERROR("Failed to load achievement data... (status code {})", (int)AchievementManager::BinStatus);

if (AchievementManager::Status != EAchStatus::Success)
if (AchievementManager::BinStatus != EAchBinStatus::Success)
{
g_corruptAchievementsMessageOpen = true;
g_corruptAchievementsMessageOpen.wait(true);
Expand Down
21 changes: 21 additions & 0 deletions UnleashedRecomp/patches/misc_patches.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <api/SWA.h>
#include <ui/game_window.h>
#include <user/achievement_manager.h>
#include <user/persistent_storage_manager.h>
#include <user/config.h>

void AchievementManagerUnlockMidAsmHook(PPCRegister& id)
Expand Down Expand Up @@ -156,3 +157,23 @@ void DisableBoostFilterMidAsmHook(PPCRegister& r11)
r11.u32 = 0;
}
}

// DLC save data flag check.
//
// The DLC checks are fundamentally broken in this game, resulting in this method always
// returning true and displaying the DLC info message when it shouldn't be.
//
// The original intent here seems to have been to display the message every time new DLC
// content is installed, but the flags in the save data never get written to properly,
// causing this function to always pass in some way.
//
// We bypass the save data completely and write to external persistent storage to store
// whether we've seen the DLC info message instead. This way we can retain the original
// broken game behaviour, whilst also providing a fix for this issue that is safe.
PPC_FUNC_IMPL(__imp__sub_824EE620);
PPC_FUNC(sub_824EE620)
{
__imp__sub_824EE620(ctx, base);

ctx.r3.u32 = PersistentStorageManager::ShouldDisplayDLCMessage(true);
}
14 changes: 8 additions & 6 deletions UnleashedRecomp/patches/resident_patches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
#include <hid/hid.h>
#include <os/logger.h>
#include <user/achievement_manager.h>
#include <user/persistent_storage_manager.h>
#include <user/config.h>
#include <app.h>

bool m_isSavedAchievementData = false;

// SWA::Message::MsgRequestStartLoading::Impl
PPC_FUNC_IMPL(__imp__sub_824DCF38);
PPC_FUNC(sub_824DCF38)
Expand Down Expand Up @@ -99,20 +98,23 @@ PPC_FUNC(sub_824E5170)

App::s_isSaving = pSaveIcon->m_IsVisible;

static bool isSavedExtraData = false;

if (pSaveIcon->m_IsVisible)
{
App::s_isSaveDataCorrupt = false;

if (!m_isSavedAchievementData)
if (!isSavedExtraData)
{
AchievementManager::Save();
AchievementManager::SaveBinary();
PersistentStorageManager::SaveBinary();

m_isSavedAchievementData = true;
isSavedExtraData = true;
}
}
else
{
m_isSavedAchievementData = false;
isSavedExtraData = false;
}
}

Expand Down
2 changes: 1 addition & 1 deletion UnleashedRecomp/user/achievement_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ bool AchievementData::VerifySignature() const

bool AchievementData::VerifyVersion() const
{
return Version == AchVersion ACH_VERSION;
return Version <= ACH_VERSION;
}

bool AchievementData::VerifyChecksum()
Expand Down
25 changes: 5 additions & 20 deletions UnleashedRecomp/user/achievement_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,12 @@

#define ACH_FILENAME "ACH-DATA"
#define ACH_SIGNATURE { 'A', 'C', 'H', ' ' }
#define ACH_VERSION { 1, 0, 0 }
#define ACH_VERSION 1
#define ACH_RECORDS 50

class AchievementData
{
public:
struct AchVersion
{
uint8_t Major;
uint8_t Minor;
uint8_t Revision;
uint8_t Reserved;

bool operator==(const AchVersion& other) const
{
return Major == other.Major &&
Minor == other.Minor &&
Revision == other.Revision;
}
};

#pragma pack(push, 1)
struct AchRecord
{
Expand All @@ -35,10 +20,10 @@ class AchievementData
#pragma pack(pop)

char Signature[4] ACH_SIGNATURE;
AchVersion Version ACH_VERSION;
uint32_t Checksum;
uint32_t Reserved;
AchRecord Records[ACH_RECORDS];
uint32_t Version{ ACH_VERSION };
uint32_t Checksum{};
uint32_t Reserved{};
AchRecord Records[ACH_RECORDS]{};

bool VerifySignature() const;
bool VerifyVersion() const;
Expand Down
41 changes: 22 additions & 19 deletions UnleashedRecomp/user/achievement_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ void AchievementManager::Reset()
Data = {};
}

void AchievementManager::Load()
bool AchievementManager::LoadBinary()
{
AchievementManager::Reset();

Status = EAchStatus::Success;
BinStatus = EAchBinStatus::Success;

auto dataPath = GetDataPath(true);

Expand All @@ -100,7 +100,7 @@ void AchievementManager::Load()
dataPath = GetDataPath(false);

if (!std::filesystem::exists(dataPath))
return;
return true;
}

std::error_code ec;
Expand All @@ -109,16 +109,16 @@ void AchievementManager::Load()

if (fileSize != dataSize)
{
Status = EAchStatus::BadFileSize;
return;
BinStatus = EAchBinStatus::BadFileSize;
return false;
}

std::ifstream file(dataPath, std::ios::binary);

if (!file)
{
Status = EAchStatus::IOError;
return;
BinStatus = EAchBinStatus::IOError;
return false;
}

AchievementData data{};
Expand All @@ -127,42 +127,43 @@ void AchievementManager::Load()

if (!data.VerifySignature())
{
Status = EAchStatus::BadSignature;
BinStatus = EAchBinStatus::BadSignature;
file.close();
return;
return false;
}

file.read((char*)&data.Version, sizeof(data.Version));

// TODO: upgrade in future if the version changes.
if (!data.VerifyVersion())
{
Status = EAchStatus::BadVersion;
BinStatus = EAchBinStatus::BadVersion;
file.close();
return;
return false;
}

file.seekg(0);
file.read((char*)&data, sizeof(data));

if (!data.VerifyChecksum())
{
Status = EAchStatus::BadChecksum;
BinStatus = EAchBinStatus::BadChecksum;
file.close();
return;
return false;
}

file.close();

memcpy(&Data, &data, dataSize);

return true;
}

void AchievementManager::Save(bool ignoreStatus)
bool AchievementManager::SaveBinary(bool ignoreStatus)
{
if (!ignoreStatus && Status != EAchStatus::Success)
if (!ignoreStatus && BinStatus != EAchBinStatus::Success)
{
LOGN_WARNING("Achievement data will not be saved in this session!");
return;
return false;
}

LOGN("Saving achievements...");
Expand All @@ -172,13 +173,15 @@ void AchievementManager::Save(bool ignoreStatus)
if (!file)
{
LOGN_ERROR("Failed to write achievement data.");
return;
return false;
}

Data.Checksum = Data.CalculateChecksum();

file.write((const char*)&Data, sizeof(AchievementData));
file.close();

Status = EAchStatus::Success;
BinStatus = EAchBinStatus::Success;

return true;
}
8 changes: 4 additions & 4 deletions UnleashedRecomp/user/achievement_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <user/achievement_data.h>

enum class EAchStatus
enum class EAchBinStatus
{
Success,
IOError,
Expand All @@ -16,7 +16,7 @@ class AchievementManager
{
public:
static inline AchievementData Data{};
static inline EAchStatus Status{};
static inline EAchBinStatus BinStatus{ EAchBinStatus::Success };

static std::filesystem::path GetDataPath(bool checkForMods)
{
Expand All @@ -29,6 +29,6 @@ class AchievementManager
static void Unlock(uint16_t id);
static void UnlockAll();
static void Reset();
static void Load();
static void Save(bool ignoreStatus = false);
static bool LoadBinary();
static bool SaveBinary(bool ignoreStatus = false);
};
13 changes: 13 additions & 0 deletions UnleashedRecomp/user/persistent_data.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "persistent_data.h"

bool PersistentData::VerifySignature() const
{
char sig[4] = EXT_SIGNATURE;

return memcmp(Signature, sig, sizeof(Signature)) == 0;
}

bool PersistentData::VerifyVersion() const
{
return Version <= EXT_VERSION;
}
Loading