Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: save #294

Merged
merged 8 commits into from
Nov 3, 2024
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
225 changes: 225 additions & 0 deletions include/RE/B/BGSSaveLoad.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
#pragma once

#include "RE/B/BSPauseRequester.h"
#include "RE/B/BSFixedString.h"
#include "RE/B/BSTArray.h"
#include "RE/B/BSTEvent.h"
#include "RE/B/BSTScatterTable.h"

namespace RE
{
namespace PlayerNameEvent
{
struct NameChangedEvent;
}

class BGSSaveLoadFile
{
public:

};

class BGSSaveLoadFileEntry
{
public:
[[nodiscard]] char* GetFileName() const
{
return fileName;
}

[[nodiscard]] char* GetPlayerName()
{
if (playerName)
return playerName;

LoadData();
return playerName;
}

[[nodiscard]] bool IsAutoSave() const
{
return fileName && !_strnicmp(fileName, "AutoSave", 8);
}

[[nodiscard]] bool IsExitSave() const
{
return fileName && !_strnicmp(fileName, "ExitSave", 8);
}

[[nodiscard]] bool IsGenerated() const
{
return fileName && !_strnicmp(fileName, "Save", 4);
}

[[nodiscard]] bool IsQuickSave() const
{
return fileName && !_strnicmp(fileName, "QuickSave", 9);
}

void LoadData()
{
using func_t = decltype(&BGSSaveLoadFileEntry::LoadData);
static REL::Relocation<func_t> func{ ID::BGSSaveLoadFileEntry::LoadData };
func(this);
}

// members
char* fileName; // 00
char* playerName; // 08
};

class BGSSaveLoadThread
{
public:
SF_RTTI_VTABLE(BGSSaveLoadThread);

struct AsyncRequest
{
using TaskFinishedCallback_t = std::add_pointer_t<void(bool a_result)>;
};
};

class BGSSaveLoadManager :
public BSTEventSink<PlayerNameEvent::NameChangedEvent>, // 000
public BSPauseRequester // 008
{
public:
SF_RTTI_VTABLE(BGSSaveLoadManager);

enum class SaveFileCategory : std::uint32_t
{
kUser = 0,
kAuto = 1,
kQuick = 2,
kExit = 3
};

enum class QueuedTask : std::uint32_t
{
kAutoSave = 0x1,
kForceSave = 0x2,
kQuickSave = 0x8,
kQuickLoad = 0x10,
kLoadGame = 0x40,
kAutoSaveCommit = 0x200,
kQuickSaveCommit = 0x400,
kBuildSaveGameList = 0x1000,
kSaveAndQuit = 0x4000,
};

virtual ~BGSSaveLoadManager(); // 00

// override (BSTEventSink)
BSEventNotifyControl ProcessEvent(const PlayerNameEvent::NameChangedEvent& a_event, BSTEventSource<PlayerNameEvent::NameChangedEvent>* a_source) override; // 01

[[nodiscard]] static auto GetSingleton()
{
static REL::Relocation<BGSSaveLoadManager**> singleton{ ID::BGSSaveLoadManager::Singleton };
return *singleton;
}

[[nodiscard]] static bool IsSaveFileNameAutoSave(const char* a_name)
{
return a_name && !_strnicmp(a_name, "AutoSave", 8);
}

[[nodiscard]] static bool IsSaveFileNameExitSave(const char* a_name)
{
return a_name && !_strnicmp(a_name, "ExitSave", 8);
}

[[nodiscard]] static bool IsSaveFileNameGenerated(const char* a_name)
{
return a_name && !_strnicmp(a_name, "Save", 4);
}

[[nodiscard]] static bool IsSaveFileNameQuickSave(const char* a_name)
{
return a_name && !_strnicmp(a_name, "QuickSave", 9);
}

bool DeleteSaveFile(const char* a_filename, void* a_unk1, bool a_skipRemainingSavesCheck)
{
using func_t = decltype(&BGSSaveLoadManager::DeleteSaveFile);
static REL::Relocation<func_t> func{ ID::BGSSaveLoadManager::DeleteSaveFile };
return func(this, a_filename, a_unk1, a_skipRemainingSavesCheck);
}

void QueueBuildSaveGameList(BGSSaveLoadThread::AsyncRequest::TaskFinishedCallback_t a_taskFinished = nullptr)
{
using func_t = decltype(&BGSSaveLoadManager::QueueBuildSaveGameList);
static REL::Relocation<func_t> func{ ID::BGSSaveLoadManager::QueueBuildSaveGameList };
func(this, a_taskFinished);
}

void QueueLoadGame(BGSSaveLoadFileEntry* a_entry)
{
queuedEntryToLoad = a_entry;
queuedTasks.set(QueuedTask::kLoadGame);
}

void QueueLoadMostRecentSaveGame()
{
if (!saveGameListBuilt) {
return QueueBuildSaveGameList([](bool a_result) {
if (a_result)
GetSingleton()->QueueLoadMostRecentSaveGame();
});
}

if (saveGameCount > 0)
QueueLoadGame(saveGameList.back());
}

void QueueSaveLoadTask(QueuedTask a_task)
{
using func_t = decltype(&BGSSaveLoadManager::QueueSaveLoadTask);
static REL::Relocation<func_t> func{ ID::BGSSaveLoadManager::QueueSaveLoadTask };
func(this, a_task);
}

[[nodiscard]] bool IsSaveGameListBuilt() const
{
return saveGameListBuilt;
}

// members
std::byte pad010[0x008]; // 010
BSTArray<BGSSaveLoadFileEntry*> saveGameList; // 018
std::byte pad028[0x008]; // 028
bool saveGameListBuilt; // 030
std::uint32_t saveGameCount; // 034
std::uint32_t currentSaveGameNumber; // 038
std::byte pad03C[0x004]; // 03C
std::uint64_t saveGameListBuildID; // 040
std::uint32_t currentAutoSaveNumber; // 048
std::byte pad04C[0x004]; // 04C
REX::EnumSet<QueuedTask> queuedTasks; // 050
std::byte pad054[0x004]; // 054
BGSSaveLoadFileEntry* queuedEntryToLoad; // 058
std::byte pad060[0x010]; // 060
char* mostRecentSaveGame; // 070
std::int32_t mostRecentSaveGameDeviceID; // 078
std::byte pad07C[0x08C]; // 07C
std::uint64_t currentPlayerID; // 108
std::uint64_t displayPlayerID; // 110
BSFixedString saveFileNameToDelete; // 118
BSTHashMap<std::uint32_t, BSFixedString> autoSaveFileNames; // 120
BSFixedString quickSaveFileName; // 158
BSFixedString exitSaveFileName; // 160
std::byte pad168[0x010]; // 168
BGSSaveLoadFile* saveLoadFile; // 178
bool returnedFromSysUtil; // 180
bool sysUtilLoadDataComplete; // 181
};
static_assert(offsetof(BGSSaveLoadManager, saveGameList) == 0x018);
static_assert(offsetof(BGSSaveLoadManager, saveGameListBuilt) == 0x030);
static_assert(offsetof(BGSSaveLoadManager, saveGameCount) == 0x034);
static_assert(offsetof(BGSSaveLoadManager, saveGameListBuildID) == 0x040);
static_assert(offsetof(BGSSaveLoadManager, queuedTasks) == 0x050);
static_assert(offsetof(BGSSaveLoadManager, mostRecentSaveGame) == 0x070);
static_assert(offsetof(BGSSaveLoadManager, currentPlayerID) == 0x108);
static_assert(offsetof(BGSSaveLoadManager, quickSaveFileName) == 0x158);
static_assert(offsetof(BGSSaveLoadManager, saveLoadFile) == 0x178);
static_assert(offsetof(BGSSaveLoadManager, sysUtilLoadDataComplete) == 0x181);
}
26 changes: 0 additions & 26 deletions include/RE/B/BGSSaveLoadManager.h

This file was deleted.

12 changes: 12 additions & 0 deletions include/RE/B/BSPauseRequester.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

namespace RE
{
class BSPauseRequester
{
public:
SF_RTTI_VTABLE(BSPauseRequester);

virtual ~BSPauseRequester();
};
}
32 changes: 32 additions & 0 deletions include/RE/E/Events.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,20 @@ namespace RE
}
};

struct BGSAppPausedEvent
{
[[nodiscard]] static BSTEventSource<BGSAppPausedEvent>* GetEventSource()
{
using func_t = decltype(&BGSAppPausedEvent::GetEventSource);
static REL::Relocation<func_t> func{ REL::ID(167011) };
return func();
}

// members
bool paused; // 00
};
static_assert(sizeof(BGSAppPausedEvent) == 0x1);

struct BGSCellGridLoadEvent
{
[[nodiscard]] static BSTEventSource<BGSCellGridLoadEvent>* GetEventSource()
Expand Down Expand Up @@ -2290,6 +2304,24 @@ namespace RE
}
};

struct PlayerDifficultySettingChanged
{
struct Event
{
[[nodiscard]] static BSTEventSource<PlayerDifficultySettingChanged::Event>* GetEventSource()
{
using func_t = decltype(&PlayerDifficultySettingChanged::Event::GetEventSource);
static REL::Relocation<func_t> func{ REL::ID(153667) };
return func();
}

// members
std::uint32_t oldDifficulty; // 00
std::uint32_t newDifficulty; // 04
};
static_assert(sizeof(PlayerDifficultySettingChanged::Event) == 0x8);
};

struct PlayerFastTravel
{
struct Event
Expand Down
9 changes: 8 additions & 1 deletion include/RE/IDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ namespace RE::ID
inline constexpr REL::ID ctor{ 101725 };
}

namespace BGSSaveLoadFileEntry
{
inline constexpr REL::ID LoadData{ 147331 };
}

namespace BGSSaveLoadGame
{
inline constexpr REL::ID SaveGame{ 147515 };
Expand All @@ -73,8 +78,10 @@ namespace RE::ID

namespace BGSSaveLoadManager
{
inline constexpr REL::ID Singleton{ 880997 };
inline constexpr REL::ID DeleteSaveFile{ 147844 };
inline constexpr REL::ID QueueBuildSaveGameList{ 147900 };
inline constexpr REL::ID QueueSaveLoadTask{ 1536882 };
inline constexpr REL::ID Singleton{ 880997 };
}

namespace BGSStoryTeller
Expand Down
8 changes: 7 additions & 1 deletion include/RE/M/Main.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,14 @@ namespace RE
}

// members
std::byte pad008[0x440]; // 008
std::byte pad008[0x020]; // 008
bool quitGame; // 028
std::byte pad029[0x005]; // 029
bool resetGame; // 02E
std::byte pad02F[0x419]; // 02F
bool isGameMenuPaused; // 448
};
static_assert(offsetof(Main, quitGame) == 0x028);
static_assert(offsetof(Main, resetGame) == 0x02E);
static_assert(offsetof(Main, isGameMenuPaused) == 0x448);
}
3 changes: 2 additions & 1 deletion include/RE/Starfield.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
#include "RE/B/BGSResourceGenerationData.h"
#include "RE/B/BGSReverbParameters.h"
#include "RE/B/BGSSaveLoadGame.h"
#include "RE/B/BGSSaveLoadManager.h"
#include "RE/B/BGSSaveLoad.h"
#include "RE/B/BGSScene.h"
#include "RE/B/BGSSecondaryDamageList.h"
#include "RE/B/BGSShaderParticleGeometryData.h"
Expand Down Expand Up @@ -197,6 +197,7 @@
#include "RE/B/BSIntrusiveRefCounted.h"
#include "RE/B/BSLock.h"
#include "RE/B/BSLog.h"
#include "RE/B/BSPauseRequester.h"
#include "RE/B/BSPointerHandle.h"
#include "RE/B/BSReflection.h"
#include "RE/B/BSResourceEnums.h"
Expand Down
Loading