Skip to content

Commit 0bf4d49

Browse files
KrzyhauThisAMJ
authored andcommitted
feat: make demoheader unique for every instance
1 parent 99bca45 commit 0bf4d49

File tree

5 files changed

+166
-0
lines changed

5 files changed

+166
-0
lines changed

src/InstanceIdentifier.cpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#include "InstanceIdentifier.hpp"
2+
3+
#include "Event.hpp"
4+
5+
#include <string>
6+
#include <filesystem>
7+
#include <fstream>
8+
#include <functional>
9+
10+
#ifdef _WIN32
11+
#include <windows.h>
12+
#else
13+
#include <fcntl.h>
14+
#include <sys/file.h>
15+
#include <unistd.h>
16+
#endif
17+
18+
19+
std::string getInstanceLockFilePath(int index) {
20+
std::string tempDir = std::filesystem::temp_directory_path().string();
21+
22+
std::string sarPath = Utils::GetSARPath();
23+
size_t sarPathHash = std::hash<std::string>{}(sarPath);
24+
25+
return Utils::ssprintf("%s/sar_instance_%zu_%d.lock", tempDir.c_str(), sarPathHash, index);
26+
}
27+
28+
#ifdef _WIN32
29+
30+
HANDLE g_instanceLockFileHandle = INVALID_HANDLE_VALUE;
31+
32+
bool tryClaimInstanceID(int index) {
33+
auto handle = CreateFileA(getInstanceLockFilePath(index).c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
34+
35+
if (handle == INVALID_HANDLE_VALUE) {
36+
return false;
37+
}
38+
39+
OVERLAPPED ol = {0};
40+
if (!LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, MAXDWORD, MAXDWORD, &ol)) {
41+
CloseHandle(handle);
42+
handle = INVALID_HANDLE_VALUE;
43+
return false;
44+
}
45+
46+
g_instanceLockFileHandle = handle;
47+
return true;
48+
}
49+
50+
void freeInstanceID() {
51+
if (g_instanceLockFileHandle == INVALID_HANDLE_VALUE) {
52+
return;
53+
}
54+
55+
UnlockFile(g_instanceLockFileHandle, 0, 0, MAXDWORD, MAXDWORD);
56+
CloseHandle(g_instanceLockFileHandle);
57+
g_instanceLockFileHandle = INVALID_HANDLE_VALUE;
58+
}
59+
60+
#else
61+
62+
int g_instanceLockFileHandle = -1;
63+
64+
bool tryClaimInstanceID(int index) {
65+
auto handle = open(getInstanceLockFilePath(index).c_str(), O_RDWR | O_CREAT, 0666);
66+
67+
if (handle == -1) {
68+
return false;
69+
}
70+
71+
if (flock(handle, LOCK_EX | LOCK_NB) != 0) {
72+
if (handle != -1) close(handle);
73+
g_instanceLockFileHandle = -1;
74+
return false;
75+
}
76+
77+
g_instanceLockFileHandle = handle;
78+
return true;
79+
}
80+
81+
void freeInstanceID() {
82+
if (g_instanceLockFileHandle == -1) {
83+
return
84+
}
85+
flock(g_instanceLockFileHandle, LOCK_UN);
86+
close(g_instanceLockFileHandle);
87+
g_instanceLockFileHandle = -1;
88+
}
89+
90+
#endif
91+
92+
93+
int g_instanceID = -1;
94+
95+
void InstanceIdentifier::Claim() {
96+
const int MAX_INSTANCES = 128;
97+
for (int i = 0; i < MAX_INSTANCES; i++) {
98+
if (!tryClaimInstanceID(i)) {
99+
continue;
100+
}
101+
102+
g_instanceID = i;
103+
return;
104+
}
105+
}
106+
107+
int InstanceIdentifier::GetID() {
108+
return g_instanceID;
109+
}
110+
111+
void InstanceIdentifier::Free() {
112+
freeInstanceID();
113+
g_instanceID = -1;
114+
}

src/InstanceIdentifier.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
namespace InstanceIdentifier {
4+
void Claim();
5+
void Free();
6+
int GetID();
7+
}

src/Modules/EngineDemoRecorder.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
#include <cstdio>
2323
#include <filesystem>
24+
#include <Hook.hpp>
25+
#include <InstanceIdentifier.hpp>
2426

2527
REDECL(EngineDemoRecorder::SetSignonState);
2628
REDECL(EngineDemoRecorder::StartRecording);
@@ -346,6 +348,30 @@ DETOUR_COMMAND(EngineDemoRecorder::record) {
346348
}
347349
}
348350

351+
Memory::Patch *g_StartupDemoFile_headerNamePatch;
352+
Memory::Patch *g_StartupDemoHeader_headerNamePatch;
353+
std::string g_uniqueDemoHeaderName;
354+
355+
void patchDemoHeaderTempFileToBeUnique() {
356+
int instanceID = InstanceIdentifier::GetID();
357+
if (instanceID == 0) {
358+
// no need to patch if we're the only instance
359+
return;
360+
}
361+
362+
g_uniqueDemoHeaderName = Utils::ssprintf("demoheader_%d.tmp", instanceID+1);
363+
364+
auto uniqueDemoHeaderName = g_uniqueDemoHeaderName.c_str();
365+
auto uniqueDemoHeaderNamePtr = (unsigned char *)&uniqueDemoHeaderName;
366+
367+
g_StartupDemoFile_headerNamePatch = new Memory::Patch();
368+
auto StartupDemoFile = Memory::Scan(engine->demorecorder->Name(), Offsets::StartupDemoFile);
369+
g_StartupDemoFile_headerNamePatch->Execute(StartupDemoFile + Offsets::StartupDemoFile_HeaderName, uniqueDemoHeaderNamePtr, 4);
370+
g_StartupDemoHeader_headerNamePatch = new Memory::Patch();
371+
auto StartupDemoHeader = Memory::Scan(engine->demorecorder->Name(), Offsets::StartupDemoHeader);
372+
g_StartupDemoHeader_headerNamePatch->Execute(StartupDemoHeader + Offsets::StartupDemoHeader_HeaderName, uniqueDemoHeaderNamePtr, 4);
373+
}
374+
349375
bool EngineDemoRecorder::Init() {
350376
auto disconnect = engine->cl->Original(Offsets::Disconnect);
351377
auto demorecorder = Memory::DerefDeref<void *>(disconnect + Offsets::demorecorder);
@@ -363,6 +389,8 @@ bool EngineDemoRecorder::Init() {
363389
this->m_bRecording = reinterpret_cast<bool *>((uintptr_t)demorecorder + Offsets::m_bRecording);
364390

365391
engine->net_time = Memory::Deref<double *>((uintptr_t)this->GetRecordingTick + Offsets::net_time);
392+
393+
patchDemoHeaderTempFileToBeUnique();
366394
}
367395

368396
Command::Hook("stop", EngineDemoRecorder::stop_callback_hook, EngineDemoRecorder::stop_callback);
@@ -371,6 +399,11 @@ bool EngineDemoRecorder::Init() {
371399
return this->hasLoaded = this->s_ClientDemoRecorder;
372400
}
373401
void EngineDemoRecorder::Shutdown() {
402+
g_StartupDemoFile_headerNamePatch->Restore();
403+
SAFE_DELETE(g_StartupDemoFile_headerNamePatch);
404+
g_StartupDemoHeader_headerNamePatch->Restore();
405+
SAFE_DELETE(g_StartupDemoHeader_headerNamePatch);
406+
374407
Interface::Delete(this->s_ClientDemoRecorder);
375408
Command::Unhook("stop", EngineDemoRecorder::stop_callback);
376409
Command::Unhook("record", EngineDemoRecorder::record_callback);

src/Offsets/Portal 2 9568.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,14 @@ OFFSET_DEFAULT(Cmd_ShutdownOff, 3, 11)
472472
OFFSET_DEFAULT(Cmd_ShutdownOff2, 10, 10)
473473

474474

475+
// EngineDemoRecorder
476+
// "demoheader.tmp"
477+
SIGSCAN_DEFAULT(StartupDemoHeader, "56 8B F1 E8 ? ? ? ? 6A 00 6A 00 68 ? ? ? ? 8D", "53 83 EC 14 8B 5C 24 ? 53 E8 ? ? ? ? 8D 43 ?")
478+
OFFSET_DEFAULT(StartupDemoHeader_HeaderName, 13, 25)
479+
SIGSCAN_DEFAULT(StartupDemoFile, "55 8B EC 81 EC 18 02 00 00 53 8B D9 80", "55 89 E5 57 56 53 81 EC 3C 02 00 00 8B 5D ? 80 BB ? ? ? ? 00")
480+
OFFSET_DEFAULT(StartupDemoFile_HeaderName, 212, 184)
481+
482+
475483
// EngineDemoPlayer
476484
SIGSCAN_DEFAULT(InterpolateDemoCommand, "55 8B EC 83 EC 10 56 8B F1 8B 4D 10 57 8B BE B4 05 00 00 83 C1 04 89 75 F4 89 7D F0 E8 ? ? ? ? 8B 4D 14 83 C1 04",
477485
"55 57 56 53 83 EC 10 8B 44 24 24 8B 5C 24 2C 8B 88 B0 05 00 00 8B 44 24 30 8D 70 04 8D 90 9C 00 00 00 89 F0 F3 0F 10 40 04")

src/SAR.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "Features/SeasonalASCII.hpp"
2121
#include "Game.hpp"
2222
#include "Hook.hpp"
23+
#include "InstanceIdentifier.hpp"
2324
#include "Interface.hpp"
2425
#include "Modules.hpp"
2526
#include "Variable.hpp"
@@ -58,6 +59,7 @@ bool SAR::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerF
5859
CrashHandler::Init();
5960

6061
curl_global_init(CURL_GLOBAL_ALL);
62+
InstanceIdentifier::Claim();
6163

6264
tier1 = new Tier1();
6365
if (tier1->Init()) {
@@ -245,6 +247,8 @@ void SAR::Unload() {
245247
tier1->Shutdown();
246248
}
247249

250+
InstanceIdentifier::Free();
251+
248252
SAFE_DELETE(sar.features)
249253
SAFE_DELETE(sar.cheats)
250254
SAFE_DELETE(sar.modules)

0 commit comments

Comments
 (0)