@@ -11,33 +11,99 @@ enum class GameVersion
1111 GTA5_ENHANCED
1212};
1313
14- inline GameVersion GetGame ()
14+ #pragma pack(push, 1)
15+ struct RSDSHeader
16+ {
17+ DWORD Signature;
18+ GUID Guid;
19+ DWORD Age;
20+ char PdbFileName[1 ];
21+ };
22+ #pragma pack(pop)
23+
24+ inline std::string GetPdbPath ()
1525{
16- static bool gotResultFromSHV = false ;
17- static GameVersion version;
26+ HMODULE hModule = GetModuleHandle (nullptr );
27+ if (!hModule)
28+ throw std::runtime_error (" Failed to get main module handle." );
29+
30+ const BYTE *base = reinterpret_cast <BYTE *>(hModule);
31+ const IMAGE_DOS_HEADER *dos = reinterpret_cast <const IMAGE_DOS_HEADER *>(base);
32+ if (dos->e_magic != IMAGE_DOS_SIGNATURE)
33+ throw std::runtime_error (" Invalid DOS signature" );
34+
35+ const IMAGE_NT_HEADERS *nt = reinterpret_cast <const IMAGE_NT_HEADERS *>(base + dos->e_lfanew );
36+ if (nt->Signature != IMAGE_NT_SIGNATURE)
37+ throw std::runtime_error (" Invalid PE signature." );
38+
39+ const IMAGE_DATA_DIRECTORY &debugData = nt->OptionalHeader .DataDirectory [IMAGE_DIRECTORY_ENTRY_DEBUG];
40+ if (debugData.VirtualAddress == 0 )
41+ throw std::runtime_error (" No debug directory found." );
42+
43+ const IMAGE_DEBUG_DIRECTORY *debugDir =
44+ reinterpret_cast <const IMAGE_DEBUG_DIRECTORY *>(base + debugData.VirtualAddress );
45+ if (debugDir->Type != IMAGE_DEBUG_TYPE_CODEVIEW)
46+ throw std::runtime_error (" Not a CodeView debug directory." );
1847
19- static auto versionFromFilename = []() -> GameVersion
48+ const BYTE *debugInfo = base + debugDir->AddressOfRawData ;
49+ const RSDSHeader *rsds = reinterpret_cast <const RSDSHeader *>(debugInfo);
50+ if (rsds->Signature != ' SDSR' )
51+ throw std::runtime_error (" Invalid RSDS signature." );
52+
53+ return std::string (rsds->PdbFileName );
54+ }
55+
56+ inline bool CheckPdbPathForVersion (const std::string &pdbPath)
57+ {
58+ if (pdbPath.find (" dev_gen9" ) != std::string::npos)
2059 {
21- WCHAR moduleName[MAX_PATH];
22- GetModuleFileName (NULL , moduleName, MAX_PATH);
23- std::wstring ws (moduleName);
24- return ws.ends_with (L" _Enhanced.exe" ) ? GameVersion::GTA5_ENHANCED : GameVersion::GTA5_LEGACY;
25- }();
60+ LOG (" Enhanced Version Detected with PDB Path: " << pdbPath);
61+ return true ;
62+ }
63+ else if (pdbPath.find (" dev_ng" ) != std::string::npos)
64+ {
65+ LOG (" Legacy Version Detected with PDB Path: " << pdbPath);
66+ return false ;
67+ }
68+
69+ throw std::runtime_error (std::string (" Unknown PDB Path: " + pdbPath));
70+ }
71+
72+ inline bool DetectByFilename ()
73+ {
74+ WCHAR moduleName[MAX_PATH];
75+ GetModuleFileName (nullptr , moduleName, MAX_PATH);
76+ std::wstring ws (moduleName);
2677
27- if (!gotResultFromSHV )
78+ if (ws. ends_with ( L" _Enhanced.exe " ) )
2879 {
29- auto v = getGameVersion ();
30- if (v != -1 )
80+ LOG (" Enhanced Version Detected With Filename Check" );
81+ return true ;
82+ }
83+
84+ LOG (" Legacy Version Detected" );
85+ return false ;
86+ }
87+
88+ inline GameVersion GetGame ()
89+ {
90+ static const GameVersion cachedVersion = []() -> GameVersion
91+ {
92+ try
3193 {
32- gotResultFromSHV = true ;
33- version = v > 1000 ? GameVersion::GTA5_ENHANCED : GameVersion::GTA5_LEGACY;
94+ const std::string pdbPath = GetPdbPath ();
95+ bool isEnhanced = CheckPdbPathForVersion (pdbPath);
96+ return isEnhanced ? GameVersion::GTA5_ENHANCED : GameVersion::GTA5_LEGACY;
3497 }
35- else
98+ catch ( const std::runtime_error &e)
3699 {
37- version = versionFromFilename;
100+ LOG (" Failed to extract PDB path! Falling back to Filename Check: " << e.what ());
101+ bool isEnhanced = DetectByFilename ();
102+ return isEnhanced ? GameVersion::GTA5_ENHANCED : GameVersion::GTA5_LEGACY;
38103 }
39- }
40- return version;
104+ }();
105+
106+ return cachedVersion;
41107}
42108
43109inline bool IsEnhanced ()
0 commit comments