feat(whoa): implement the ability to shut down the client gracefully, saving CVars upon exit

This commit is contained in:
phaneron 2025-04-15 20:00:50 -04:00
parent 17ccf2a8bb
commit 0105c72da0
11 changed files with 186 additions and 25 deletions

View file

@ -8,6 +8,7 @@
const char* s_filename = nullptr;
bool CVar::m_needsSave;
bool CVar::m_initialized;
TSHashTable<CVar, HASHKEY_STRI> CVar::s_registeredCVars;
CVar* CVar::Lookup(const char* name) {
@ -34,6 +35,10 @@ CVar* CVar::LookupRegistered(const char* name) {
}
CVar* CVar::Register(const char* name, const char* help, uint32_t flags, const char* value, HANDLER_FUNC fcn, uint32_t category, bool a7, void* arg, bool a9) {
if (!name || !*name || !value) {
return nullptr;
}
auto cv = s_registeredCVars.Ptr(name);
if (cv) {
@ -280,6 +285,7 @@ int32_t CVar::Load(const char* filename) {
void CVar::Initialize(const char* filename) {
STORM_ASSERT(filename);
s_filename = filename;
m_initialized = 1;
// Get data path
char path[STORM_MAX_PATH] = {0};
@ -296,6 +302,72 @@ void CVar::Initialize(const char* filename) {
CVar::Load(s_filename);
}
int32_t CVar::IterateForArchive(uint32_t a1, uint32_t a2, ITERATE_FUNC cb, void* param) {
auto cvar = s_registeredCVars.Head();
while (cvar) {
if (cvar->m_flags & 0x1) {
if (!(cvar->m_flags & 0x80) && (cvar->m_flags & 0x30) == a1 && (cvar->m_flags & a2) == 0) {
const char* value;
if ((value = cvar->m_latchedValue.GetString()) ||
(value = cvar->m_stringValue.GetString()) ||
(value = cvar->m_defaultValue.GetString())) {
auto defaultvalue = cvar->m_defaultValue.GetString();
if (!defaultvalue || SStrCmp(value, defaultvalue, STORM_MAX_STR)) {
if (!cb(cvar->m_key.m_str, value, param)) {
return 0;
}
}
}
}
}
cvar = s_registeredCVars.Next(cvar);
}
return 1;
}
bool CVar::SaveCvar(const char* key, const char* value, void* param) {
char buffer[STORM_MAX_PATH];
SStrPrintf(buffer, sizeof(buffer), "SET %s \"%s\"\n", key, value);
uint32_t byteswritten = 0;
OsWriteFile(static_cast<HOSFILE>(param), buffer, SStrLen(buffer), &byteswritten);
return byteswritten != 0;
}
int32_t CVarSaveFile() {
if (!CVar::m_needsSave) {
return 1;
}
char name[STORM_MAX_PATH];
CVar::m_needsSave = false;
SStrCopy(name, "WTF\\", sizeof(name));
SStrPack(name, s_filename, sizeof(name));
int32_t result = 0;
auto file = OsCreateFile(name, OS_GENERIC_WRITE, 0, OS_CREATE_ALWAYS, OS_FILE_ATTRIBUTE_NORMAL, OS_FILE_TYPE_DEFAULT);
if (file != HOSFILE_INVALID) {
result = CVar::IterateForArchive(0, 0, CVar::SaveCvar, file);
OsCloseFile(file);
}
return result;
}
void CVar::Destroy() {
m_initialized = 0;
CVarSaveFile();
ConsoleCommandUnregister("set");
ConsoleCommandUnregister("cvar_reset");
ConsoleCommandUnregister("cvar_default");
ConsoleCommandUnregister("cvarlist");
s_registeredCVars.Clear();
}
int32_t CvarResetCommandHandler(const char* command, const char* arguments) {
char cvarName[256] = {0};
auto string = arguments;
@ -395,7 +467,7 @@ int32_t SetCommandHandler(const char* command, const char* arguments) {
}
cvar->m_modified++;
if (!(cvar->m_flags & 0x2)) {
if ((cvar->m_flags & 0x2)) {
cvar->m_latchedValue.Copy(cvarValue);
CVar::m_needsSave = true;
} else if (!(cvar->m_flags & 0x4)) {

View file

@ -1,32 +1,36 @@
#ifndef CONSOLE_CVAR_HPP
#define CONSOLE_CVAR_HPP
#include <cstdint>
#include <common/String.hpp>
#include <storm/Hash.hpp>
#include <bc/os/File.hpp>
#include <common/String.hpp>
#include <cstdint>
#include <storm/Hash.hpp>
#define CONSOLE_CVAR_MAX_LINE 2048
class CVar : public TSHashObject<CVar, HASHKEY_STRI> {
public:
typedef bool (*ITERATE_FUNC)(const char*, const char*, void*);
typedef bool (*HANDLER_FUNC)(CVar*, const char*, const char*, void*);
// Static variables
static TSHashTable<CVar, HASHKEY_STRI> s_registeredCVars;
static bool m_needsSave;
static bool m_initialized;
// Static functions
static CVar* Lookup(const char* name);
static CVar* LookupRegistered(const char* name);
static CVar* Register(const char* name, const char* help, uint32_t flags, const char* value, HANDLER_FUNC fcn, uint32_t category, bool a7, void* arg, bool a9);
static void Initialize(const char* filename);
static void Initialize(const char* filename);
static int32_t IterateForArchive(uint32_t a1, uint32_t a2, ITERATE_FUNC cb, void* param);
static void Destroy();
static int32_t Load(const char* filename);
static int32_t Load(HOSFILE fileHandle);
static bool SaveCvar(const char* key, const char* value, void* param);
// Member variables
uint32_t m_category = 0;
uint32_t m_flags = 0;
uint32_t m_flags = 0;
RCString m_stringValue;
float m_floatValue = 0.0;
int32_t m_intValue = 0;
@ -36,7 +40,7 @@ class CVar : public TSHashObject<CVar, HASHKEY_STRI> {
RCString m_latchedValue;
RCString m_help;
bool (*m_callback)(CVar*, const char*, const char*, void*) = nullptr;
void* m_arg = nullptr;
void* m_arg = nullptr;
// Member functions
CVar();
@ -50,7 +54,6 @@ class CVar : public TSHashObject<CVar, HASHKEY_STRI> {
int32_t Update();
};
int32_t SetCommandHandler(const char* command, const char* arguments);
int32_t CvarResetCommandHandler(const char* command, const char* arguments);
int32_t CvarDefaultCommandHandler(const char* command, const char* arguments);

View file

@ -31,8 +31,6 @@ const char* ConsoleCommandHistory(uint32_t index);
uint32_t ConsoleCommandHistoryDepth();
int32_t ConsoleCommandRegister(const char* command, COMMANDHANDLER handler, CATEGORY category, const char* helpText);
void ConsoleInitializeCommonCommand();
void ConsoleInitializeDebugCommand();

View file

@ -35,5 +35,5 @@ void ConsoleSetHotKey(KEY hotkey) {
}
void ConsolePostClose() {
EventPostCloseEx(EventGetCurrentContext());
EventPostClose();
}