Skip to content

Commit e9ae96c

Browse files
committed
Fix AppID 730 verification issue & add customizable key bindings for menu/exit
1 parent dca1233 commit e9ae96c

File tree

9 files changed

+208
-56
lines changed

9 files changed

+208
-56
lines changed

ErScripts/Config.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ void Config::load(const std::string& filename) {
104104
read(json["gradient-manager"]["saturation"], gradient.saturation);
105105
read(json["gradient-manager"]["value"], gradient.value);
106106

107+
/* ErScripts Binds */
108+
read(json["er-scripts"]["menu"]["bind"], erScriptsMenuBind);
109+
read(json["er-scripts"]["exit"]["bind"], erScriptsExitBind);
110+
107111
/* Vsync */
108112
read(json["vsync"]["state"], vsyncState);
109113
}
@@ -208,6 +212,10 @@ void Config::save(const std::string& filename) const {
208212
/* Vsync */
209213
json["vsync"]["state"] = vsyncState;
210214

215+
/* ErScripts Binds */
216+
json["er-scripts"]["menu"]["bind"] = erScriptsMenuBind;
217+
json["er-scripts"]["exit"]["bind"] = erScriptsExitBind;
218+
211219
if (!std::filesystem::exists("configs"))
212220
std::filesystem::create_directory("configs");
213221

ErScripts/Config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ class Config {
105105
/* Vsync */
106106
bool vsyncState{ false };
107107

108+
/* ErScripts Binds */
109+
int erScriptsMenuBind{ VK_INSERT };
110+
int erScriptsExitBind{ VK_END };
111+
108112
private:
109113
template <typename T>
110114
void read(const nlohmann::json& src, T& dest) {

ErScripts/ErScripts.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,26 @@ void ErScripts::InitBinds() {
349349
const auto timeoutDuration = std::chrono::seconds(10);
350350
bool timerStart = false;
351351

352+
int prevExitBind = cfg->erScriptsExitBind;
353+
std::chrono::steady_clock::time_point changeTime;
354+
bool isDelayActive = false;
355+
352356
while (!globals::finish) {
353-
if (GetAsyncKeyState(VK_END) & 0x8000) globals::finish = true;
357+
if (prevExitBind != cfg->erScriptsExitBind) {
358+
prevExitBind = cfg->erScriptsExitBind;
359+
changeTime = std::chrono::steady_clock::now();
360+
isDelayActive = true;
361+
}
362+
else if (isDelayActive) {
363+
auto now = std::chrono::steady_clock::now();
364+
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - changeTime).count();
365+
if (elapsed >= 2000) {
366+
isDelayActive = false;
367+
}
368+
}
369+
else {
370+
if (GetAsyncKeyState(cfg->erScriptsExitBind) & 0x8000) globals::finish = true;
371+
}
354372

355373
if (GetWindowState() && GetCursorState() && globals::localPlayerIsActivityPlaying) {
356374
std::wstring cfg = config + +L"1.cfg";

ErScripts/Menu.cpp

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@ const char* GetKeyName(int virtualKeyCode) {
55
static char keyName[128] = { 0 };
66

77
switch (virtualKeyCode) {
8-
case VK_LBUTTON: return "LMOUSE";
9-
case VK_RBUTTON: return "RMOUSE";
10-
case VK_MBUTTON: return "MOUSE3";
11-
case VK_XBUTTON1: return "MOUSE4";
12-
case VK_XBUTTON2: return "MOUSE5";
13-
case VK_PRIOR:
14-
case VK_NEXT:
15-
case VK_END:
16-
case VK_HOME:
8+
case VK_LBUTTON: return "LMOUSE";
9+
case VK_RBUTTON: return "RMOUSE";
10+
case VK_MBUTTON: return "MOUSE3";
11+
case VK_XBUTTON1: return "MOUSE4";
12+
case VK_XBUTTON2: return "MOUSE5";
13+
case VK_END: return "END";
14+
case VK_HOME: return "HOME";
15+
case VK_INSERT: return "INSERT";
16+
case VK_DELETE: return "DELETE";
17+
case VK_PRIOR: return "PAGE UP";
18+
case VK_NEXT: return "PAGE DOWN";
1719
case VK_LEFT:
1820
case VK_UP:
1921
case VK_RIGHT:
@@ -22,8 +24,6 @@ const char* GetKeyName(int virtualKeyCode) {
2224
case VK_PRINT:
2325
case VK_EXECUTE:
2426
case VK_SNAPSHOT:
25-
case VK_INSERT:
26-
case VK_DELETE:
2727
case VK_HELP:
2828
case VK_LWIN:
2929
case VK_RWIN:
@@ -68,6 +68,10 @@ inline const char* selfKickKeyName = GetKeyName(cfg->selfKickBind);
6868
inline bool selfKickButtonState = false;
6969
inline const char* autoStopKeyName = GetKeyName(cfg->autoStopBind);
7070
inline bool autoStopButtonState = false;
71+
inline const char* erScriptsMenuKeyName = GetKeyName(cfg->erScriptsMenuBind);
72+
inline bool erScriptsMenuButtonState = false;
73+
inline const char* erScriptsExitKeyName = GetKeyName(cfg->erScriptsExitBind);
74+
inline bool erScriptsExitButtonState = false;
7175
inline char killSayText[256]{};
7276
inline char killSoundFileName[256]{};
7377
inline char roundStartAlertFileName[256]{};
@@ -168,6 +172,8 @@ void Overlay::Menu() noexcept {
168172
dropBombKeyName = GetKeyName(cfg->dropBombBind);
169173
selfKickKeyName = GetKeyName(cfg->selfKickBind);
170174
autoStopKeyName = GetKeyName(cfg->autoStopBind);
175+
erScriptsMenuKeyName = GetKeyName(cfg->erScriptsMenuBind);
176+
erScriptsExitKeyName = GetKeyName(cfg->erScriptsExitBind);
171177

172178
if (ImGui::FindWindowByName(" Bomb Timer"))
173179
ImGui::SetWindowPos(" Bomb Timer", { cfg->bombTimerPos[0], cfg->bombTimerPos[1] });
@@ -494,6 +500,39 @@ void Overlay::CustomBindsMenu() noexcept {
494500
}
495501
Hotkey(&selfKickButtonState, &selfKickKeyName, &cfg->selfKickBind);
496502

503+
ImGui::TableNextRow();
504+
ImGui::TableSetColumnIndex(0);
505+
ImGui::Spacing();
506+
ImGui::Separator();
507+
ImGui::Spacing();
508+
ImGui::TableSetColumnIndex(1);
509+
ImGui::Spacing();
510+
ImGui::Separator();
511+
ImGui::Spacing();
512+
513+
/* ErScripts Binds */
514+
/* Menu */
515+
ImGui::TableNextRow();
516+
ImGui::TableSetColumnIndex(0);
517+
ImGui::Text("Menu Bind ");
518+
ImGui::TableSetColumnIndex(1);
519+
erScriptsMenuKeyName = GetKeyName(cfg->erScriptsMenuBind);
520+
if (ImGui::Button(std::format("{}##MenuBind", erScriptsMenuKeyName).c_str(), ImVec2(80.0f, 22.0f))) {
521+
erScriptsMenuButtonState = !erScriptsMenuButtonState;
522+
}
523+
Hotkey(&erScriptsMenuButtonState, &erScriptsMenuKeyName, &cfg->erScriptsMenuBind);
524+
525+
/* Exit */
526+
ImGui::TableNextRow();
527+
ImGui::TableSetColumnIndex(0);
528+
ImGui::Text("Exit Bind ");
529+
ImGui::TableSetColumnIndex(1);
530+
erScriptsExitKeyName = GetKeyName(cfg->erScriptsExitBind);
531+
if (ImGui::Button(std::format("{}##ExitBind", erScriptsExitKeyName).c_str(), ImVec2(80.0f, 22.0f))) {
532+
erScriptsExitButtonState = !erScriptsExitButtonState;
533+
}
534+
Hotkey(&erScriptsExitButtonState, &erScriptsExitKeyName, &cfg->erScriptsExitBind);
535+
497536
ImGui::EndTable();
498537
}
499538

ErScripts/Overlay.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,11 @@ void Overlay::Handler() noexcept {
332332
bool inCaptureBypass = !cfg->captureBypassState;
333333
int width_old, height_old, posX_old, posY_old;
334334

335+
bool curMenuState = (GetAsyncKeyState(cfg->erScriptsMenuBind) & 0x8000) != 0;
336+
int prevMenuBind = cfg->erScriptsMenuBind;
337+
std::chrono::steady_clock::time_point changeTime;
338+
bool isDelayActive = false;
339+
335340
ErScripts::GetWindowInfo(width_old, height_old, posX_old, posY_old);
336341

337342
CleanupRenderTarget();
@@ -342,8 +347,21 @@ void Overlay::Handler() noexcept {
342347
RegisterRawInput(window_handle);
343348

344349
while (!globals::finish) {
345-
// Toggle menu
346-
bool curMenuState = (GetAsyncKeyState(VK_INSERT) & 0x8000) != 0;
350+
if (prevMenuBind != cfg->erScriptsMenuBind) {
351+
prevMenuBind = cfg->erScriptsMenuBind;
352+
changeTime = std::chrono::steady_clock::now();
353+
isDelayActive = true;
354+
}
355+
else if (isDelayActive) {
356+
auto now = std::chrono::steady_clock::now();
357+
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - changeTime).count();
358+
if (elapsed >= 1000) {
359+
isDelayActive = false;
360+
}
361+
}
362+
else {
363+
curMenuState = (GetAsyncKeyState(cfg->erScriptsMenuBind) & 0x8000) != 0;
364+
}
347365

348366
// Check if key state changed from not pressed to pressed
349367
if (curMenuState && !prevMenuState) {

ErScripts/SteamTools.cpp

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -124,36 +124,45 @@ std::wstring SteamTools::trim(std::wstring_view str) {
124124
return std::wstring(str.substr(first, last - first + 1));
125125
}
126126

127-
std::map<std::string, std::wstring> SteamTools::parseVdfContent(std::wstring_view content) {
128-
std::map<std::string, std::wstring> appPaths;
127+
std::map<std::string, std::vector<std::wstring>> SteamTools::parseVdfContent(std::wstring_view content) {
128+
std::map<std::string, std::vector<std::wstring>> appPaths;
129129
std::wistringstream iss(content.data());
130130
std::wstring line, currentPath;
131-
bool inAppsSection = false;
132131
bool inLibraryFolder = false;
132+
bool inAppsSection = false;
133133

134134
while (std::getline(iss, line)) {
135-
line = trim(line);
135+
line.erase(0, line.find_first_not_of(L" \t")); // Trim left
136+
line.erase(line.find_last_not_of(L" \t") + 1); // Trim right
136137
if (line.empty()) continue;
137138

138-
if (line.starts_with(L"\"") && line[1] >= L'0' && line[1] <= L'9' && line[2] == L'"') {
139+
if (line.size() >= 3 && line[0] == L'"' && iswdigit(line[1]) && line[2] == L'"') {
139140
inLibraryFolder = true;
141+
currentPath.clear();
140142
continue;
141143
}
142144

143145
if (inLibraryFolder && line == L"{") continue;
144146

145-
if (line.starts_with(L"\"path\"")) {
146-
std::wistringstream lineStream(line);
147-
std::wstring key, value;
148-
if (!(lineStream >> std::quoted(key) >> std::quoted(value)) || key != L"path") {
149-
throw VdfParseError("Invalid path line format");
147+
if (inLibraryFolder && line.starts_with(L"\"path\"")) {
148+
size_t start = line.find(L'"', 7);
149+
size_t end = line.find(L'"', start + 1);
150+
if (start == std::wstring::npos || end == std::wstring::npos) {
151+
throw VdfParseError("Malformed path line: " + std::string(line.begin(), line.end()));
152+
}
153+
currentPath = line.substr(start + 1, end - start - 1);
154+
std::replace(currentPath.begin(), currentPath.end(), L'/', L'\\');
155+
std::wstring normalizedPath;
156+
for (size_t i = 0; i < currentPath.length(); ++i) {
157+
if (i > 0 && currentPath[i] == L'\\' && currentPath[i - 1] == L'\\') continue;
158+
normalizedPath += currentPath[i];
150159
}
151-
currentPath = value;
152-
std::replace(currentPath.begin(), currentPath.end(), L'\\', L'/');
160+
currentPath = normalizedPath;
153161
Logger::logSuccess(std::format(L"Found library path: {}", currentPath));
162+
continue;
154163
}
155164

156-
if (line == L"\"apps\"") {
165+
if (inLibraryFolder && line == L"\"apps\"") {
157166
inAppsSection = true;
158167
continue;
159168
}
@@ -165,62 +174,98 @@ std::map<std::string, std::wstring> SteamTools::parseVdfContent(std::wstring_vie
165174

166175
if (inLibraryFolder && !inAppsSection && line == L"}") {
167176
inLibraryFolder = false;
168-
currentPath.clear();
169177
continue;
170178
}
171179

172180
if (inAppsSection && line.starts_with(L"\"")) {
173-
std::wistringstream lineStream(line);
174-
std::wstring wAppId, size;
175-
if (!(lineStream >> std::quoted(wAppId) >> std::quoted(size))) {
176-
throw VdfParseError("Invalid app entry format");
181+
size_t appIdStart = line.find(L'"');
182+
size_t appIdEnd = line.find(L'"', appIdStart + 1);
183+
size_t sizeStart = line.find(L'"', appIdEnd + 1);
184+
size_t sizeEnd = line.find(L'"', sizeStart + 1);
185+
if (appIdEnd == std::wstring::npos || sizeEnd == std::wstring::npos) {
186+
throw VdfParseError("Malformed app entry: " + std::string(line.begin(), line.end()));
177187
}
178-
std::string appId(wAppId.begin(), wAppId.end()); // AppID remains ASCII
188+
189+
std::wstring wAppId = line.substr(appIdStart + 1, appIdEnd - appIdStart - 1);
190+
std::string appId(wAppId.begin(), wAppId.end());
179191
if (!appId.empty() && !currentPath.empty()) {
180-
appPaths[appId] = currentPath + L"/steamapps/common/";
181-
//Logger::logSuccess(std::format(L"Found app {} at {}", wAppId, appPaths[appId]));
192+
fs::path basePath = fs::path(currentPath) / L"steamapps" / L"common";
193+
std::wstring normalizedPath = basePath.wstring();
194+
std::replace(normalizedPath.begin(), normalizedPath.end(), L'/', L'\\');
195+
std::wstring singleSlashPath;
196+
for (size_t i = 0; i < normalizedPath.length(); ++i) {
197+
if (i > 0 && normalizedPath[i] == L'\\' && normalizedPath[i - 1] == L'\\') continue;
198+
singleSlashPath += normalizedPath[i];
199+
}
200+
appPaths[appId].push_back(singleSlashPath);
201+
// Logger::logInfo(std::format(L"App {} potentially at: {}", wAppId, singleSlashPath));
182202
}
183203
}
184204
}
205+
185206
return appPaths;
186207
}
187208

188209
std::optional<std::wstring> SteamTools::getAppInstallPath(std::string_view appId, const GameConfig& config) {
189210
try {
190-
auto steamPath = getSteamInstallPath();
191-
auto vdfPath = fs::path(steamPath) / L"steamapps" / L"libraryfolders.vdf";
192-
Logger::logInfo(std::format(L"Looking for VDF at: {}", vdfPath.wstring()));
211+
std::wstring steamPath = getSteamInstallPath();
212+
if (steamPath.empty()) {
213+
Logger::logWarning(L"Could not determine Steam installation path");
214+
return std::nullopt;
215+
}
216+
Logger::logSuccess(std::format(L"Steam install path from registry: {}", steamPath));
217+
218+
fs::path vdfPath = fs::path(steamPath) / L"steamapps" / L"libraryfolders.vdf";
219+
std::wstring vdfPathStr = vdfPath.wstring();
220+
std::replace(vdfPathStr.begin(), vdfPathStr.end(), L'/', L'\\');
221+
Logger::logInfo(std::format(L"Looking for VDF at: {}", vdfPathStr));
193222

194223
std::wifstream file(vdfPath);
195224
if (!file.is_open()) {
196-
throw std::runtime_error("Failed to open VDF file: " + std::string(vdfPath.string().begin(), vdfPath.string().end()));
225+
Logger::logWarning(L"Failed to open VDF file: " + vdfPathStr);
226+
return std::nullopt;
197227
}
198228

199229
std::wstringstream wss;
200230
wss << file.rdbuf();
201231
std::wstring content = wss.str();
202-
Logger::logSuccess("Successfully read VDF file");
232+
file.close();
233+
Logger::logSuccess(L"Successfully read VDF file");
203234

204235
auto appPaths = parseVdfContent(content);
205-
auto it = appPaths.find(appId.data());
236+
auto it = appPaths.find(std::string(appId));
206237
if (it == appPaths.end()) {
207-
Logger::logWarning(std::format(L"AppID {} not found in libraryfolders.vdf", std::wstring(appId.begin(), appId.end())));
238+
Logger::logWarning(std::format(L"AppID {} not found in VDF", std::wstring(appId.begin(), appId.end())));
208239
return std::nullopt;
209240
}
210241

211-
for (const auto& folder : config.possibleFolders) {
212-
std::wstring fullPath = it->second + folder;
213-
if (fs::exists(fullPath) && fs::is_directory(fullPath)) {
214-
Logger::logSuccess(std::format(L"Found {} at: {}", std::wstring(appId.begin(), appId.end()), fullPath));
215-
return fullPath;
242+
const auto& potentialPaths = it->second;
243+
for (const auto& basePath : potentialPaths) {
244+
Logger::logInfo(std::format(L"Exploring library path: {}", basePath));
245+
for (const auto& folder : config.possibleFolders) {
246+
fs::path fullPath = fs::path(basePath) / folder;
247+
std::wstring fullPathStr = fullPath.wstring();
248+
std::replace(fullPathStr.begin(), fullPathStr.end(), L'/', L'\\');
249+
Logger::logInfo(std::format(L"Checking: {}", fullPathStr));
250+
if (fs::exists(fullPath)) {
251+
if (fs::is_directory(fullPath)) {
252+
Logger::logSuccess(std::format(L"Found {} at: {}",
253+
std::wstring(appId.begin(), appId.end()), fullPathStr));
254+
return fullPathStr;
255+
}
256+
else {
257+
Logger::logInfo(std::format(L"Path {} exists but is not a directory", fullPathStr));
258+
}
259+
}
216260
}
217261
}
218262

219-
Logger::logWarning(std::format(L" Found AppID {} but couldn't verify any known folder", std::wstring(appId.begin(), appId.end())));
263+
Logger::logWarning(std::format(L"AppID {} found in VDF but no valid installation folder located",
264+
std::wstring(appId.begin(), appId.end())));
220265
return std::nullopt;
221266
}
222267
catch (const std::exception& e) {
223-
Logger::logWarning(std::format(" Error: {}", e.what()));
268+
Logger::logWarning(std::format("Error getting app install path: {}", e.what()));
224269
return std::nullopt;
225270
}
226271
}

ErScripts/SteamTools.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class SteamTools {
8383
static std::wstring getSteamConfigPath();
8484

8585
// Parse VDF content into a map of app IDs to their base paths
86-
static std::map<std::string, std::wstring> parseVdfContent(std::wstring_view content);
86+
static std::map<std::string, std::vector<std::wstring>> parseVdfContent(std::wstring_view content);
8787

8888
// Parse launch options from a VDF file for a specific AppID
8989
static std::wstring parseLaunchOptions(const std::wstring& filePath, std::string_view appId);

0 commit comments

Comments
 (0)