-
Notifications
You must be signed in to change notification settings - Fork 5
/
LaunchGame.cpp
157 lines (137 loc) · 3.39 KB
/
LaunchGame.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include "LaunchGame.h"
#include "GameForms.h"
#include "Settings.h"
#include "GECKUtility.h"
#include <fstream>
#include <sstream>
#include <string>
namespace LaunchGame
{
constexpr const char* GECK_LAUNCH_FILENAME = "GeckLaunchGame.txt";
void WriteLaunchAtCellFile(UInt32 time, TESObjectCELL* cell)
{
std::ofstream outputFile(GECK_LAUNCH_FILENAME, std::ios::out);
if (!outputFile)
{
Console_Print("Unable to open file for writing.");
return;
}
auto editorId = cell->GetEditorID();
if (editorId && *editorId)
{
outputFile << time << ',' << editorId;
}
}
// Function to read the game launch data from the file
bool ReadLaunchAtCellFile(LaunchGameData& data)
{
std::ifstream inputFile(GECK_LAUNCH_FILENAME);
if (!inputFile)
{
return false;
}
// Read the entire line from the file
std::string line;
if (!std::getline(inputFile, line))
{
return false;
}
// Create a string stream from the read line to parse the values
std::istringstream iss(line);
std::string token;
// Retrieve and convert the first token to DWORD (timestamp)
if (std::getline(iss, token, ','))
{
data.timestamp = std::stoul(token);
}
else
{
return false;
}
// Retrieve the second token as the editor ID
if (std::getline(iss, token, ','))
{
data.cellEditorId = token;
}
else
{
return false;
}
return true;
}
bool IsGeckRunning()
{
return FindWindowA("Garden of Eden Creation Kit", 0);
}
std::string sCellEditorID;
bool ReadCellEditorID()
{
constexpr UInt32 TIMESTAMP_MAX_DELAY = 5 * 1000;
LaunchGameData launchData;
if (ReadLaunchAtCellFile(launchData))
{
if (IsGeckRunning() && (GetTickCount() - launchData.timestamp) < TIMESTAMP_MAX_DELAY)
{
sCellEditorID = launchData.cellEditorId;
}
DeleteFile(GECK_LAUNCH_FILENAME);
}
return !sCellEditorID.empty();
}
void OnGameMainMenu()
{
if (!sCellEditorID.empty())
{
ThisCall(0x93DB60, *(UInt32**)0x11DEA3C, sCellEditorID.c_str(), 0); // CenterOnCell
}
}
void GameMessageHandler(NVSEMessagingInterface::Message* msg)
{
if (msg->type == NVSEMessagingInterface::kMessage_MainGameLoop)
{
static int FramesWaited;
static bool bDoOnce;
if (FramesWaited < 10)
{
++FramesWaited;
}
else if (!bDoOnce)
{
bDoOnce = true;
OnGameMainMenu();
}
}
}
bool OnGamePluginLoad(const NVSEInterface* nvse)
{
if (ReadCellEditorID())
{
auto pluginHandle = nvse->GetPluginHandle();
// setup DirectInput hooks
NVSEMessagingInterface* msgIntfc = (NVSEMessagingInterface*)nvse->QueryInterface(kInterface_Messaging);
msgIntfc->RegisterListener(pluginHandle, "NVSE", GameMessageHandler);
return true;
}
return false;
}
void Launch()
{
char exePath[MAX_PATH];
auto commandLineDir = (const char*)0xECFE30;
_snprintf(exePath, sizeof(exePath), "%s\\%s", commandLineDir, config.sLaunchExeName);
exePath[sizeof(exePath) - 1] = '\0'; // ensure exePath is null terminated
PROCESS_INFORMATION processInfo;
ZeroMemory(&processInfo, sizeof(processInfo));
if (_CreateProcessA(exePath, &processInfo))
{
auto cell = RenderWindow::GetCurrentCell();
if (cell && GetAsyncKeyState(VK_SHIFT) < 0)
{
Console_Print("Launched game - process id: %d");
WriteLaunchAtCellFile(GetTickCount(), cell);
}
}
if (processInfo.hProcess) CloseHandle(processInfo.hProcess);
if (processInfo.hThread) CloseHandle(processInfo.hThread);
}
}