Files
Rcjy/Rcjy/Framework/Backend/Config/Config.cpp
T
2026-06-08 15:49:35 +08:00

399 lines
11 KiB
C++

#define _CRT_SECURE_NO_WARNINGS
#include "Config.h"
#include "../Utilities/Utilities.h"
#include "../../Backend/Globalincludes.h"
#include "../Main/Main.h"
#include <filesystem>
#include <array>
namespace {
std::string color_to_string(const int col[4]) {
return std::to_string(col[0]) + "," + std::to_string(col[1]) + "," + std::to_string(col[2]) + "," + std::to_string(col[3]);
}
std::array<int, 4> string_to_color(const std::string& s) {
static auto split = [](const std::string& str, const char* del) -> std::vector<std::string>
{
char* pTempStr = _strdup(str.c_str());
char* pWord = strtok(pTempStr, del);
std::vector<std::string> dest;
while (pWord != NULL)
{
dest.push_back(pWord);
pWord = strtok(NULL, del);
}
free(pTempStr);
return dest;
};
std::vector<std::string> col = split(s, ",");
return { std::stoi(col.at(0)), std::stoi(col.at(1)), std::stoi(col.at(2)), std::stoi(col.at(3)) };
}
}
void CConfig::GetFileName(char* _buffer, bool db) {
strcpy_s(_buffer, 255, this->s["config_name"]);
}
void CConfig::GetFilePath(char* _buffer, bool db) {
char buffer[MAX_PATH];
char filename[255];
GetFileName(filename);
GetCurrentDirectoryA(MAX_PATH, buffer);
if (!db)
sprintf_s(buffer, "%s\\configs\\%s.cfg", buffer, filename);
else
sprintf_s(buffer, "%s\\configs", buffer);
strcpy_s(_buffer, 260, buffer);
}
void CConfig::LoadDefaults() {
Refresh();
CConfig* cfg = CConfig::get();
{
cfg->b["isAdmin"] = IsRunningAsAdmin();
}
{
cfg->b["time"] = false;
cfg->i["time_format"] = 0;
cfg->b["text_border"] = false;
cfg->i["time_text_size"] = 45;
cfg->i["time_text_character_spacing"] = 0;
cfg->c["time_text_Color"][0] = 255;
cfg->c["time_text_Color"][1] = 255;
cfg->c["time_text_Color"][2] = 255;
cfg->c["time_text_Color"][3] = 255;
cfg->f["time_x_pos"] = 0.0f;
cfg->f["time_y_pos"] = 0.0f;
cfg->c["text_border_Color"][0] = 0;
cfg->c["text_border_Color"][1] = 0;
cfg->c["text_border_Color"][2] = 0;
cfg->c["text_border_Color"][3] = 255;
}
{
cfg->b["keyboard_control"] = false;
cfg->i["Caps_control"] = 0;
cfg->i["Num_control"] = 0;
strncpy_s(cfg->s["keyboard_whitelist"], 255, "", 254);
}
{
cfg->c["MenuColor"][0] = 163;
cfg->c["MenuColor"][1] = 212;
cfg->c["MenuColor"][2] = 31;
cfg->c["MenuColor"][3] = 255;
strncpy_s(cfg->s["menu_key_bind"], 255, "163,97", 254); // Ctrl + 1 (top row, NumLock-independent)
GamesenseMenuFramework::Globals::MultiKeyCache("menu_key_bind") = "163,97";
cfg->i["menu_keystyle"] = 4;
cfg->i["menu_key"] = VK_INSERT; // fallback single-key
cfg->i["menu_scale"] = 0;
cfg->b["lock_menu_layout"] = true;
cfg->b["show_console"] = true;
}
}
// --- menu.cfg tracking helpers (must be before Load/Save) ---
static void GetMenuCfgPath(char* buf, int bufSize) {
GetCurrentDirectoryA(bufSize, buf);
sprintf_s(buf, bufSize, "%s\\configs\\menu.configs", buf);
}
static void WriteMenuCfg(const char* configName, bool hasManual) {
char path[MAX_PATH];
GetMenuCfgPath(path, MAX_PATH);
WritePrivateProfileStringA("Config", "LastConfig", configName, path);
WritePrivateProfileStringA("Config", "HasManualSave", hasManual ? "1" : "0", path);
}
static void ReadMenuCfg(char* outName, int outSize, bool* outHasManual) {
char path[MAX_PATH];
GetMenuCfgPath(path, MAX_PATH);
GetPrivateProfileStringA("Config", "LastConfig", "", outName, outSize, path);
*outHasManual = GetPrivateProfileIntA("Config", "HasManualSave", 0, path) != 0;
}
// ---
void CConfig::AutoLoad() {
char lastConfig[255] = "";
bool hasManual;
ReadMenuCfg(lastConfig, sizeof(lastConfig), &hasManual);
this->hasManualSave = hasManual;
// Try the last known config first
if (lastConfig[0] != 0) {
strcpy_s(this->s["config_name"], lastConfig);
char filepath[MAX_PATH];
GetFilePath(filepath);
if (GetFileAttributesA(filepath) != INVALID_FILE_ATTRIBUTES) {
Load();
return;
}
}
// Fallback: find an existing profile-*.cfg
char configsPath[MAX_PATH];
GetFilePath(configsPath, true);
if (std::filesystem::exists(configsPath)) {
std::string bestDefault;
for (auto& entry : std::filesystem::directory_iterator(configsPath)) {
if (entry.path().extension() == ".cfg") {
std::string name = entry.path().stem().string();
if (name.find("profile-") == 0 && name > bestDefault)
bestDefault = name;
}
}
if (!bestDefault.empty()) {
strcpy_s(this->s["config_name"], bestDefault.c_str());
Load();
return;
}
}
// Nothing found — use in-memory defaults (already set by LoadDefaults)
this->s["config_name"][0] = 0;
}
void CConfig::AutoSave() {
if (this->hasManualSave) {
if (this->s["config_name"][0] != 0)
Save();
} else {
if (this->s["config_name"][0] == 0)
strcpy_s(this->s["config_name"], "profile-auto");
Save();
}
WriteMenuCfg(this->s["config_name"], this->hasManualSave);
}
void CConfig::Load() {
if (this->s["config_name"][0] == 0)
return;
this->Current = this->s["config_name"];
Refresh();
char file_path[MAX_PATH] = { 0 };
GetFilePath(file_path);
// Read b (bool) entries from INI
for (auto& e : b) {
if (e.first.find("_") == 0) continue;
e.second = GetPrivateProfileIntA("b", e.first.c_str(), e.second, file_path) != 0;
}
// Read i (int) entries from INI
for (auto& e : i) {
if (e.first.find("_") == 0) continue;
e.second = GetPrivateProfileIntA("i", e.first.c_str(), e.second, file_path);
}
// Read f (float) entries from INI
for (auto& e : f) {
if (e.first.find("_") == 0) continue;
char buffer[64] = { 0 };
GetPrivateProfileStringA("f", e.first.c_str(), "", buffer, 63, file_path);
if (buffer[0] != 0)
e.second = (float)atof(buffer);
}
// Read c (color) entries from INI
for (auto& e : c) {
if (e.first.find("_") == 0) continue;
char buffer[64] = { 0 };
GetPrivateProfileStringA("c", e.first.c_str(), "", buffer, 63, file_path);
if (buffer[0] != 0) {
auto col = string_to_color(buffer);
e.second[0] = col[0];
e.second[1] = col[1];
e.second[2] = col[2];
e.second[3] = col[3];
}
}
// Read m (map) entries from INI
for (auto& e : m) {
if (e.first.find("_") == 0) continue;
char buffer[4096] = { 0 };
GetPrivateProfileStringA("m", e.first.c_str(), "", buffer, 4095, file_path);
if (buffer[0] != 0) {
e.second.clear();
char* ctx = nullptr;
char* token = strtok_s(buffer, "|", &ctx);
while (token) {
int key = 0, val = 0;
if (sscanf_s(token, "%d:%d", &key, &val) == 2)
e.second[key] = val != 0;
token = strtok_s(nullptr, "|", &ctx);
}
}
}
// Read s (string) entries from INI
for (auto& e : s) {
if (e.first == "config_name") continue;
GetPrivateProfileStringA("s", e.first.c_str(), e.second, e.second, 255, file_path);
}
// Sync MultiKeyCache with loaded s values so IsBindActive uses the correct bindings
for (auto& e : s) {
if (e.first.size() > 5 && e.first.compare(e.first.size() - 5, 5, "_bind") == 0) {
GamesenseMenuFramework::Globals::MultiKeyCache(e.first) = e.second;
}
}
WriteMenuCfg(this->s["config_name"], this->hasManualSave);
}
void CConfig::Save() {
if (this->s["config_name"][0] == 0)
return;
char configs_path[260];
GetFilePath(configs_path, true);
std::filesystem::create_directories(configs_path);
char file_path[MAX_PATH] = { 0 };
GetFilePath(file_path);
Misc::Utilities->Console_Log("Saving config: %s", file_path);
for (auto e : b) {
if (!std::string(e.first).find("_")) continue;
char buffer[8] = { 0 }; _itoa(e.second, buffer, 10);
WritePrivateProfileStringA("b", e.first.c_str(), std::string(buffer).c_str(), file_path);
}
for (auto e : i) {
if (!std::string(e.first).find("_")) continue;
char buffer[32] = { 0 }; _itoa(e.second, buffer, 10);
WritePrivateProfileStringA("i", e.first.c_str(), std::string(buffer).c_str(), file_path);
}
for (auto e : f) {
if (!std::string(e.first).find("_")) continue;
char buffer[64] = { 0 }; sprintf(buffer, "%f", e.second);
WritePrivateProfileStringA("f", e.first.c_str(), std::string(buffer).c_str(), file_path);
}
for (auto e : c) {
if (!std::string(e.first).find("_")) continue;
WritePrivateProfileStringA("c", e.first.c_str(), color_to_string(e.second).c_str(), file_path);
}
for (auto e : m) {
if (!std::string(e.first).find("_")) continue;
std::string vs = "";
for (auto v : e.second)
vs += std::to_string(v.first) + ":" + std::to_string(v.second) + "|";
WritePrivateProfileStringA("m", e.first.c_str(), vs.c_str(), file_path);
}
for (auto e : s) {
if (e.first == "config_name") continue;
if (e.second[0] == 0) continue;
WritePrivateProfileStringA("s", e.first.c_str(), e.second, file_path);
}
this->hasManualSave = true;
WriteMenuCfg(this->s["config_name"], true);
Refresh();
}
void CConfig::Delete() {
if (this->s["config_name"][0] == 0)
return;
char path[260];
GetFilePath(path);
std::remove(path);
Refresh();
}
void CConfig::Refresh() {
this->List.clear();
char path[260];
GetFilePath(path, true);
if (!std::filesystem::exists(path))
return;
for (auto& entry : std::filesystem::directory_iterator(path)) {
if (entry.path().extension() == (".cfg")) {
auto path = entry.path();
auto path_text = entry.path().string();
auto filename = path.filename().string();
if (filename != "tempbuffer")
this->List.push_back(filename.substr(0, filename.length() - 4));
}
}
}
bool CConfig::IsBindActive(std::string key) {
auto g = GamesenseMenuFramework::Globals::Gui_Ctx;
if (!g) return false;
switch (this->i[key + "style"]) {
case 0:
// Always on
return true;
case 1:
// On hotkey (held)
return g->KeyState[this->i[key]];
case 2:
// Toggle (rising edge)
return g->KeyState[this->i[key]] && !g->PrevKeyState[this->i[key]];
case 3:
// Off hotkey (not held)
return !g->KeyState[this->i[key]];
case 4:
{
// Multi-key: all stored keys must be held simultaneously
std::string multiStr = GamesenseMenuFramework::Globals::MultiKeyCache(key + "_bind");
if (multiStr.empty()) {
multiStr = this->s[key + "_bind"];
if (!multiStr.empty() && multiStr[0] != 0)
GamesenseMenuFramework::Globals::MultiKeyCache(key + "_bind") = multiStr;
}
if (multiStr.empty() || multiStr[0] == 0) return false;
const char* p = multiStr.c_str();
while (*p) {
int vk = atoi(p);
if (vk > 0 && vk < 256) {
bool held = g->KeyState[vk];
if (!held) {
// Accept either left/right modifier
int pair = 0;
if (vk == 162) pair = 163;
else if (vk == 163) pair = 162;
else if (vk == 160) pair = 161;
else if (vk == 161) pair = 160;
else if (vk == 164) pair = 165;
else if (vk == 165) pair = 164;
if (pair) held = g->KeyState[pair];
}
if (!held) return false;
}
const char* comma = strchr(p, ',');
if (!comma) break;
p = comma + 1;
}
return true;
}
default:
return true;
}
}