Commit b3858a82 authored by NTAuthority's avatar NTAuthority

convar configuration saving

parent eb4c79d8
Pipeline #47 skipped
......@@ -45,6 +45,8 @@ struct Constraints<T, std::enable_if_t<std::is_arithmetic<T>::value>>
}
};
void MarkConsoleVarModified(ConsoleVariableManager* manager, const std::string& name);
template<typename T>
class ConsoleVariableEntry : public ConsoleVariableEntryBase
{
......@@ -119,6 +121,13 @@ public:
return false;
}
// update modified flags if changed
if (!ConsoleArgumentTraits<T>::Equal()(m_curValue, newValue))
{
// indirection as manager isn't declared by now
MarkConsoleVarModified(m_manager, m_name);
}
m_curValue = newValue;
if (m_trackingVar)
......@@ -153,8 +162,8 @@ private:
enum ConsoleVariableFlags
{
ConVar_None = 0,
ConVar_Archive = 0x1
ConVar_Archive = 0x1,
ConVar_Modified = 2
};
class ConsoleVariableManager : public ConsoleVariableManagerProxy
......@@ -162,6 +171,10 @@ class ConsoleVariableManager : public ConsoleVariableManagerProxy
public:
using THandlerPtr = std::shared_ptr<internal::ConsoleVariableEntryBase>;
using TVariableCB = std::function<void(const std::string& name, int flags, const THandlerPtr& variable)>;
using TWriteLineCB = std::function<void(const std::string& line)>;
public:
ConsoleVariableManager(console::Context* context);
......@@ -174,6 +187,14 @@ public:
bool Process(const std::string& commandName, const ProgramArguments& arguments);
THandlerPtr FindEntryRaw(const std::string& name);
void AddEntryFlags(const std::string& name, int flags);
void RemoveEntryFlags(const std::string& name, int flags);
void ForAllVariables(const TVariableCB& callback, int flagMask = 0xFFFFFFFF);
void SaveConfiguration(const TWriteLineCB& writeLineFunction);
inline console::Context* GetParentContext()
{
......
......@@ -30,6 +30,8 @@ public:
void ExecuteBuffer();
void SaveConfigurationIfNeeded(const std::string& path);
inline ConsoleCommandManager* GetCommandManager()
{
return m_commandManager.get();
......@@ -68,5 +70,7 @@ ProgramArguments Tokenize(const std::string& line);
void AddToBuffer(const std::string& text);
void ExecuteBuffer();
void SaveConfigurationIfNeeded(const std::string& path);
}
}
\ No newline at end of file
#include <StdInc.h>
#include <vfs/Manager.h>
#include <Console.CommandHelpers.h>
namespace krt
{
static ConsoleCommand execCommand("exec", [] (const std::string& path)
{
vfs::StreamPtr stream = vfs::OpenRead(path);
if (!stream)
{
printf("No such config file: %s\n", path.c_str());
return;
}
std::vector<uint8_t> data = stream->ReadToEnd();
data.push_back('\n'); // add a newline at the end
console::AddToBuffer(std::string(reinterpret_cast<char*>(&data[0]), data.size()));
console::ExecuteBuffer();
});
}
\ No newline at end of file
......@@ -11,17 +11,26 @@ ConsoleVariableManager::ConsoleVariableManager(console::Context* parentContext)
{
// weird order is to prevent recursive locking
{
auto lock = shared_lock_acquire<std::shared_timed_mutex>(m_mutex);
Entry* entry = nullptr;
auto oldVariable = m_entries.find(variable);
{
auto lock = shared_lock_acquire<std::shared_timed_mutex>(m_mutex);
auto oldVariable = m_entries.find(variable);
if (oldVariable != m_entries.end())
{
entry = &oldVariable->second;
}
}
if (oldVariable != m_entries.end())
if (entry)
{
oldVariable->second.variable->SetValue(value);
entry->variable->SetValue(value);
if (archive)
{
oldVariable->second.flags |= ConVar_Archive;
entry->flags |= ConVar_Archive;
}
return;
......@@ -97,6 +106,63 @@ void ConsoleVariableManager::Unregister(int token)
}
}
void ConsoleVariableManager::AddEntryFlags(const std::string& name, int flags)
{
auto lock = exclusive_lock_acquire<std::shared_timed_mutex>(m_mutex);
auto it = m_entries.find(name);
if (it != m_entries.end())
{
it->second.flags |= flags;
}
}
void ConsoleVariableManager::RemoveEntryFlags(const std::string& name, int flags)
{
auto lock = exclusive_lock_acquire<std::shared_timed_mutex>(m_mutex);
auto it = m_entries.find(name);
if (it != m_entries.end())
{
it->second.flags &= ~(flags);
}
}
void ConsoleVariableManager::ForAllVariables(const TVariableCB& callback, int flagMask)
{
// store first so we don't have to deal with recursive locks
std::vector<std::tuple<std::string, int, THandlerPtr>> iterationList;
{
auto lock = exclusive_lock_acquire<std::shared_timed_mutex>(m_mutex);
for (auto& entry : m_entries)
{
// if flags match the mask
if ((entry.second.flags & flagMask) != 0)
{
iterationList.push_back(std::make_tuple(entry.second.name, entry.second.flags, entry.second.variable));
}
}
}
// and call the iterator with each tuple
for (const auto& entry : iterationList)
{
apply(callback, entry);
}
}
void ConsoleVariableManager::SaveConfiguration(const TWriteLineCB& writeLineFunction)
{
ForAllVariables([&] (const std::string& name, int flags, const THandlerPtr& variable)
{
writeLineFunction("seta \"" + name + "\" \"" + variable->GetValue() + "\"");
}, ConVar_Archive);
}
bool ConsoleVariableManager::Process(const std::string& commandName, const ProgramArguments& arguments)
{
// we currently don't process any variables specifically
......@@ -107,4 +173,12 @@ ConsoleVariableManager* ConsoleVariableManager::GetDefaultInstance()
{
return console::GetDefaultContext()->GetVariableManager();
}
namespace internal
{
void MarkConsoleVarModified(ConsoleVariableManager* manager, const std::string& name)
{
manager->AddEntryFlags(name, ConVar_Modified);
}
}
}
\ No newline at end of file
......@@ -3,6 +3,8 @@
#include <Console.Commands.h>
#include <Console.Variables.h>
#include <vfs/Manager.h>
#include <sstream>
namespace krt
......@@ -108,6 +110,60 @@ void Context::ExecuteBuffer()
}
}
static void SaveConfiguration(const std::string& path, ConsoleVariableManager* manager)
{
vfs::DevicePtr device = vfs::GetDevice(path);
if (device)
{
auto handle = device->Create(path);
if (handle != INVALID_DEVICE_HANDLE)
{
auto writeLine = [&] (const std::string& line)
{
const char newLine[] = { '\r', '\n' };
device->Write(handle, line.c_str(), line.size());
device->Write(handle, newLine, sizeof(newLine));
};
// write a cutesy warning
writeLine("// generated by ATG, do not modify unless meow");
// save the actual configuration
manager->SaveConfiguration(writeLine);
device->Close(handle);
}
}
}
void Context::SaveConfigurationIfNeeded(const std::string& path)
{
// check if the configuration was saved already
static bool wasSavedBefore = false;
// mark a flag to see if any variables are modified (or if we haven't done our initial save)
int numModifiedVars = (wasSavedBefore) ? 0 : 1;
GetVariableManager()->ForAllVariables([&] (const std::string& name, int, const ConsoleVariableManager::THandlerPtr&)
{
// increment the counter
++numModifiedVars;
// remove the modified flag as well
GetVariableManager()->RemoveEntryFlags(name, ConVar_Modified);
}, ConVar_Modified);
if (numModifiedVars > 0)
{
SaveConfiguration(path, GetVariableManager());
wasSavedBefore = true;
}
}
// default context functions
Context* GetDefaultContext()
{
......@@ -143,6 +199,11 @@ void ExecuteBuffer()
return GetDefaultContext()->ExecuteBuffer();
}
void SaveConfigurationIfNeeded(const std::string& path)
{
return GetDefaultContext()->SaveConfigurationIfNeeded(path);
}
ProgramArguments Tokenize(const std::string& line)
{
int i = 0;
......
......@@ -47,6 +47,9 @@ class Game
GameUniversePtr GetUniverse(const std::string& name);
private:
void MountUserDirectory();
private:
float dT;
uint32_t lastFrameTime;
......
#include "StdInc.h"
#include "Game.h"
#include <vfs/Manager.h>
#include <vfs/RelativeDevice.h>
#include <windows.h>
#include <shlwapi.h>
#include <shlobj.h>
#pragma comment(lib, "shlwapi.lib")
namespace krt
{
static void AppendPathComponent(std::wstring& value, const wchar_t* component)
{
value += component;
if (GetFileAttributesW(value.c_str()) == INVALID_FILE_ATTRIBUTES)
{
CreateDirectoryW(value.c_str(), nullptr);
}
}
void Game::MountUserDirectory()
{
PWSTR saveBasePath;
// get the 'Saved Games' shell directory
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_SavedGames, 0, nullptr, &saveBasePath)))
{
// create a STL string and free the used memory
std::wstring savePath(saveBasePath);
CoTaskMemFree(saveBasePath);
// append our path components
AppendPathComponent(savePath, L"\\AMDDesign");
AppendPathComponent(savePath, L"\\ATG");
// append a final separator
savePath += L"\\";
// and turn the path into a mount
vfs::DevicePtr device = std::make_shared<vfs::RelativeDevice>(ToNarrow(savePath));
vfs::Mount(device, "user:/");
}
}
}
\ No newline at end of file
......@@ -41,6 +41,12 @@ Game::Game(void) : streaming(GAME_NUM_STREAMING_CHANNELS), texManager(streaming)
gta::attachPlugins();
// mount the user directory
MountUserDirectory();
// run config.cfg
console::ExecuteSingleCommand(ProgramArguments{ "exec", "user:/config.cfg" });
// Detect where the game is installed.
// For now, I guess we do it manually.
......@@ -153,6 +159,9 @@ void Game::Run()
// execute the command buffer for the global console
console::ExecuteBuffer();
// try saving changed console variables
console::SaveConfigurationIfNeeded("user:/config.cfg");
// whatever else might come to mind
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment