feat: add config persistence with INI load/save and debug mode
This commit is contained in:
parent
baabc7878e
commit
974442b78c
|
|
@ -2,4 +2,7 @@
|
||||||
x86
|
x86
|
||||||
x64
|
x64
|
||||||
Debug
|
Debug
|
||||||
Release
|
Release
|
||||||
|
CFramework.ini
|
||||||
|
CFramework_imgui.ini
|
||||||
|
.serena/
|
||||||
|
|
@ -97,6 +97,9 @@ namespace
|
||||||
|
|
||||||
void CFramework::RenderInfo()
|
void CFramework::RenderInfo()
|
||||||
{
|
{
|
||||||
|
if (!g.g_DebugMode)
|
||||||
|
return;
|
||||||
|
|
||||||
const auto snapshot = GetDynamicSnapshot();
|
const auto snapshot = GetDynamicSnapshot();
|
||||||
const bool snapshotFresh = snapshot && IsSnapshotFresh(snapshot->capturedAt);
|
const bool snapshotFresh = snapshot && IsSnapshotFresh(snapshot->capturedAt);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,282 @@
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
Globals g;
|
Globals g;
|
||||||
|
|
||||||
|
#define CFW_CONFIG_BOOL_FIELDS(X) \
|
||||||
|
X(g_DebugMode) \
|
||||||
|
X(g_ESP) \
|
||||||
|
X(g_ESP_Item) \
|
||||||
|
X(g_ESP_Corpse) \
|
||||||
|
X(g_ESP_Container) \
|
||||||
|
X(g_ESP_Exfil) \
|
||||||
|
X(g_ESP_Grenade) \
|
||||||
|
X(g_ESP_Line) \
|
||||||
|
X(g_ESP_Box) \
|
||||||
|
X(g_ESP_BoxFilled) \
|
||||||
|
X(g_ESP_Skeleton) \
|
||||||
|
X(g_ESP_Distance) \
|
||||||
|
X(g_ESP_Name) \
|
||||||
|
X(g_ESP_HealthBar) \
|
||||||
|
X(g_InfStamina) \
|
||||||
|
X(g_NoFallDamage) \
|
||||||
|
X(g_NoSway) \
|
||||||
|
X(g_NoRecoil) \
|
||||||
|
X(g_NoMalfunction) \
|
||||||
|
X(g_Aim) \
|
||||||
|
X(g_AimTargetPMC) \
|
||||||
|
X(g_AimTargetScav) \
|
||||||
|
X(g_AimTargetBoss) \
|
||||||
|
X(g_AimIgnoreHealth) \
|
||||||
|
X(g_AimForce) \
|
||||||
|
X(g_AimDrawFov) \
|
||||||
|
X(g_AimDrawTarget) \
|
||||||
|
X(g_Recoil) \
|
||||||
|
X(g_StreamProof) \
|
||||||
|
X(g_Crosshair)
|
||||||
|
|
||||||
|
#define CFW_CONFIG_INT_FIELDS(X) \
|
||||||
|
X(g_ESP_BoxStyle) \
|
||||||
|
X(g_AimMethod) \
|
||||||
|
X(g_AimBone) \
|
||||||
|
X(g_RecoilInterval) \
|
||||||
|
X(g_AimMcOffset) \
|
||||||
|
X(g_AimRotOffset) \
|
||||||
|
X(g_CrosshairSize) \
|
||||||
|
X(g_CrosshairType) \
|
||||||
|
X(g_MenuKey) \
|
||||||
|
X(g_AimKey0) \
|
||||||
|
X(g_AimKey1) \
|
||||||
|
X(g_AimKey2)
|
||||||
|
|
||||||
|
#define CFW_CONFIG_FLOAT_FIELDS(X) \
|
||||||
|
X(g_ESP_MaxDistance) \
|
||||||
|
X(g_ESP_MaxItemDistance) \
|
||||||
|
X(g_ESP_MaxContainerDistance) \
|
||||||
|
X(g_AimFov) \
|
||||||
|
X(g_AimSmooth) \
|
||||||
|
X(g_AimSens) \
|
||||||
|
X(g_AimMaxSpeed) \
|
||||||
|
X(g_AimMaxDist) \
|
||||||
|
X(g_RecoilStrength)
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using ConfigValues = std::unordered_map<std::string, std::string>;
|
||||||
|
|
||||||
|
std::filesystem::path GetConfigPath()
|
||||||
|
{
|
||||||
|
wchar_t modulePath[MAX_PATH]{};
|
||||||
|
const DWORD length = GetModuleFileNameW(nullptr, modulePath, MAX_PATH);
|
||||||
|
if (length == 0 || length >= MAX_PATH)
|
||||||
|
return std::filesystem::path(L"CFramework.ini");
|
||||||
|
|
||||||
|
return std::filesystem::path(modulePath).parent_path() / L"CFramework.ini";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trim(std::string& value)
|
||||||
|
{
|
||||||
|
const std::size_t first = value.find_first_not_of(" \t\r\n");
|
||||||
|
if (first == std::string::npos)
|
||||||
|
{
|
||||||
|
value.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t last = value.find_last_not_of(" \t\r\n");
|
||||||
|
value = value.substr(first, last - first + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigValues ReadValues(std::ifstream& input)
|
||||||
|
{
|
||||||
|
ConfigValues values;
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(input, line))
|
||||||
|
{
|
||||||
|
Trim(line);
|
||||||
|
if (line.empty() || line.front() == '#' || line.front() == ';')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const std::size_t separator = line.find('=');
|
||||||
|
if (separator == std::string::npos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string key = line.substr(0, separator);
|
||||||
|
std::string value = line.substr(separator + 1);
|
||||||
|
Trim(key);
|
||||||
|
Trim(value);
|
||||||
|
if (!key.empty())
|
||||||
|
values[key] = value;
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadBool(const ConfigValues& values, const char* key, bool& output)
|
||||||
|
{
|
||||||
|
const auto it = values.find(key);
|
||||||
|
if (it == values.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (it->second == "1" || it->second == "true" || it->second == "TRUE")
|
||||||
|
{
|
||||||
|
output = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (it->second == "0" || it->second == "false" || it->second == "FALSE")
|
||||||
|
{
|
||||||
|
output = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadInt(const ConfigValues& values, const char* key, int& output)
|
||||||
|
{
|
||||||
|
const auto it = values.find(key);
|
||||||
|
if (it == values.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::size_t consumed = 0;
|
||||||
|
const int parsed = std::stoi(it->second, &consumed, 0);
|
||||||
|
if (consumed != it->second.size())
|
||||||
|
return false;
|
||||||
|
output = parsed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadFloat(const ConfigValues& values, const char* key, float& output)
|
||||||
|
{
|
||||||
|
const auto it = values.find(key);
|
||||||
|
if (it == values.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::size_t consumed = 0;
|
||||||
|
const float parsed = std::stof(it->second, &consumed);
|
||||||
|
if (consumed != it->second.size() || !std::isfinite(parsed))
|
||||||
|
return false;
|
||||||
|
output = parsed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteBool(std::ofstream& output, const char* key, bool value)
|
||||||
|
{
|
||||||
|
output << key << '=' << (value ? 1 : 0) << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteInt(std::ofstream& output, const char* key, int value)
|
||||||
|
{
|
||||||
|
output << key << '=' << value << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteFloat(std::ofstream& output, const char* key, float value)
|
||||||
|
{
|
||||||
|
output << key << '=' << std::setprecision(9) << value << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClampLoadedConfig()
|
||||||
|
{
|
||||||
|
g.g_ESP_BoxStyle = (std::clamp)(g.g_ESP_BoxStyle, 0, 1);
|
||||||
|
g.g_AimMethod = (std::clamp)(g.g_AimMethod, 0, 1);
|
||||||
|
g.g_AimBone = (std::clamp)(g.g_AimBone, 0, 2);
|
||||||
|
g.g_RecoilInterval = (std::clamp)(g.g_RecoilInterval, 1, 1000);
|
||||||
|
g.g_AimMcOffset = (std::clamp)(g.g_AimMcOffset, 0, 0x1000);
|
||||||
|
g.g_AimRotOffset = (std::clamp)(g.g_AimRotOffset, 0, 0x1000);
|
||||||
|
g.g_CrosshairSize = (std::clamp)(g.g_CrosshairSize, 1, 32);
|
||||||
|
g.g_CrosshairType = (std::clamp)(g.g_CrosshairType, 0, 1);
|
||||||
|
g.g_MenuKey = (std::clamp)(g.g_MenuKey, 1, 255);
|
||||||
|
g.g_AimKey0 = (std::clamp)(g.g_AimKey0, 1, 255);
|
||||||
|
g.g_AimKey1 = (std::clamp)(g.g_AimKey1, 1, 255);
|
||||||
|
g.g_AimKey2 = (std::clamp)(g.g_AimKey2, 1, 255);
|
||||||
|
|
||||||
|
g.g_ESP_MaxDistance = (std::clamp)(g.g_ESP_MaxDistance, 0.f, 5000.f);
|
||||||
|
g.g_ESP_MaxItemDistance = (std::clamp)(g.g_ESP_MaxItemDistance, 0.f, 5000.f);
|
||||||
|
g.g_ESP_MaxContainerDistance = (std::clamp)(g.g_ESP_MaxContainerDistance, 0.f, 5000.f);
|
||||||
|
g.g_AimFov = (std::clamp)(g.g_AimFov, 1.f, 2000.f);
|
||||||
|
g.g_AimSmooth = (std::clamp)(g.g_AimSmooth, 0.f, 100.f);
|
||||||
|
g.g_AimSens = (std::clamp)(g.g_AimSens, 0.01f, 20.f);
|
||||||
|
g.g_AimMaxSpeed = (std::clamp)(g.g_AimMaxSpeed, 0.f, 2000.f);
|
||||||
|
g.g_AimMaxDist = (std::clamp)(g.g_AimMaxDist, 0.f, 5000.f);
|
||||||
|
g.g_RecoilStrength = (std::clamp)(g.g_RecoilStrength, 0.f, 100.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
bool Load()
|
||||||
|
{
|
||||||
|
std::ifstream input(GetConfigPath(), std::ios::in);
|
||||||
|
if (!input.is_open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const ConfigValues values = ReadValues(input);
|
||||||
|
|
||||||
|
#define READ_BOOL(field) ReadBool(values, #field, g.field);
|
||||||
|
CFW_CONFIG_BOOL_FIELDS(READ_BOOL)
|
||||||
|
#undef READ_BOOL
|
||||||
|
|
||||||
|
#define READ_INT(field) ReadInt(values, #field, g.field);
|
||||||
|
CFW_CONFIG_INT_FIELDS(READ_INT)
|
||||||
|
#undef READ_INT
|
||||||
|
|
||||||
|
#define READ_FLOAT(field) ReadFloat(values, #field, g.field);
|
||||||
|
CFW_CONFIG_FLOAT_FIELDS(READ_FLOAT)
|
||||||
|
#undef READ_FLOAT
|
||||||
|
|
||||||
|
ClampLoadedConfig();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Save()
|
||||||
|
{
|
||||||
|
std::ofstream output(GetConfigPath(), std::ios::out | std::ios::trunc);
|
||||||
|
if (!output.is_open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
output << "# CFramework configuration v1\n";
|
||||||
|
output << "version=1\n";
|
||||||
|
|
||||||
|
#define WRITE_BOOL(field) WriteBool(output, #field, g.field);
|
||||||
|
CFW_CONFIG_BOOL_FIELDS(WRITE_BOOL)
|
||||||
|
#undef WRITE_BOOL
|
||||||
|
|
||||||
|
#define WRITE_INT(field) WriteInt(output, #field, g.field);
|
||||||
|
CFW_CONFIG_INT_FIELDS(WRITE_INT)
|
||||||
|
#undef WRITE_INT
|
||||||
|
|
||||||
|
#define WRITE_FLOAT(field) WriteFloat(output, #field, g.field);
|
||||||
|
CFW_CONFIG_FLOAT_FIELDS(WRITE_FLOAT)
|
||||||
|
#undef WRITE_FLOAT
|
||||||
|
|
||||||
|
output.flush();
|
||||||
|
return output.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* FileName()
|
||||||
|
{
|
||||||
|
return "CFramework.ini";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CFW_CONFIG_BOOL_FIELDS
|
||||||
|
#undef CFW_CONFIG_INT_FIELDS
|
||||||
|
#undef CFW_CONFIG_FLOAT_FIELDS
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ struct Globals
|
||||||
|
|
||||||
// System
|
// System
|
||||||
bool g_StreamProof = false;
|
bool g_StreamProof = false;
|
||||||
|
bool g_DebugMode = false;
|
||||||
bool g_Crosshair = true;
|
bool g_Crosshair = true;
|
||||||
int g_CrosshairSize = 3;
|
int g_CrosshairSize = 3;
|
||||||
int g_CrosshairType = 0;
|
int g_CrosshairType = 0;
|
||||||
|
|
@ -81,4 +82,11 @@ struct Globals
|
||||||
int g_AimKey2 = VK_F9; // 键盘触发键 (鼠标键检测异常时的替代, 按住触发)
|
int g_AimKey2 = VK_F9; // 键盘触发键 (鼠标键检测异常时的替代, 按住触发)
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Globals g;
|
extern Globals g;
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
bool Load();
|
||||||
|
bool Save();
|
||||||
|
const char* FileName();
|
||||||
|
}
|
||||||
|
|
@ -43,7 +43,7 @@ bool Overlay::CreateOverlay()
|
||||||
IMGUI_CHECKVERSION();
|
IMGUI_CHECKVERSION();
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||||
io.IniFilename = nullptr;
|
io.IniFilename = "CFramework_imgui.ini";
|
||||||
io.LogFilename = nullptr;
|
io.LogFilename = nullptr;
|
||||||
|
|
||||||
LoadStyle();
|
LoadStyle();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "Cheat/Framework.h"
|
#include "Cheat/Framework.h"
|
||||||
#include "Framework/Overlay/Overlay.h"
|
#include "Framework/Overlay/Overlay.h"
|
||||||
#include "Framework/Input/Input.h"
|
#include "Framework/Input/Input.h"
|
||||||
|
#include "Framework/Config/Config.h"
|
||||||
#pragma comment(lib, "freetype.lib")
|
#pragma comment(lib, "freetype.lib")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -47,6 +48,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||||
// 使用每监视器 DPI,保证 overlay、GameRect 和 W2S 使用同一套物理像素坐标。
|
// 使用每监视器 DPI,保证 overlay、GameRect 和 W2S 使用同一套物理像素坐标。
|
||||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||||
|
|
||||||
|
// 先读取用户配置,再创建 overlay 和启动 worker。
|
||||||
|
Config::Load();
|
||||||
|
|
||||||
// ウィンドウをベースにして初期化を行う
|
// ウィンドウをベースにして初期化を行う
|
||||||
if (!m.AttachProcess("EscapeFromTarkov", InitMode::WINDOW_TITLE)) // 詳細は Memory/Memory.h を参照
|
if (!m.AttachProcess("EscapeFromTarkov", InitMode::WINDOW_TITLE)) // 詳細は Memory/Memory.h を参照
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -60,7 +64,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||||
|
|
||||||
// ImGui io setting
|
// ImGui io setting
|
||||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||||
io.IniFilename = nullptr;
|
io.IniFilename = "CFramework_imgui.ini";
|
||||||
io.LogFilename = nullptr;
|
io.LogFilename = nullptr;
|
||||||
|
|
||||||
// Load Font
|
// Load Font
|
||||||
|
|
@ -104,8 +108,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||||
staticSnapshotThread.join();
|
staticSnapshotThread.join();
|
||||||
|
|
||||||
cheat->ResetFeatureOverrides();
|
cheat->ResetFeatureOverrides();
|
||||||
|
Config::Save();
|
||||||
overlay->DestroyOverlay();
|
overlay->DestroyOverlay();
|
||||||
m.DetachProcess();
|
m.DetachProcess();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue