about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--App/Main.cpp41
-rw-r--r--Source/Memory.cpp40
-rw-r--r--Source/Memory.h17
3 files changed, 56 insertions, 42 deletions
diff --git a/App/Main.cpp b/App/Main.cpp index b018892..5adf22d 100644 --- a/App/Main.cpp +++ b/App/Main.cpp
@@ -17,11 +17,10 @@ public:
17}; 17};
18 18
19#define EXE_NAME L"witness64_d3d11.exe" 19#define EXE_NAME L"witness64_d3d11.exe"
20#define PROC_ATTACH 0x401 20#define HEARTBEAT 0x401
21#define RANDOMIZE_READY 0x402 21#define RANDOMIZE_READY 0x402
22#define RANDOMIZING 0403 22#define RANDOMIZING 0403
23#define RANDOMIZE_DONE 0x404 23#define RANDOMIZE_DONE 0x404
24#define CHECK_NEWGAME 0x405
25 24
26// Globals 25// Globals
27HWND g_hwnd; 26HWND g_hwnd;
@@ -40,24 +39,25 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
40 PostQuitMessage(0); 39 PostQuitMessage(0);
41 } else if (message == WM_COMMAND || message == WM_TIMER) { 40 } else if (message == WM_COMMAND || message == WM_TIMER) {
42 switch (LOWORD(wParam)) { 41 switch (LOWORD(wParam)) {
43 case PROC_ATTACH: 42 case HEARTBEAT:
44 if (!g_witnessProc->Initialize(EXE_NAME)) { 43 SetTimer(g_hwnd, HEARTBEAT, 1000, NULL);
45 SetTimer(g_hwnd, PROC_ATTACH, 1000, NULL); // Retry in 1s 44 // Potential improvement: Change this call to be part of the HEARTBEAT message.
46 } else { 45 switch (g_witnessProc->Heartbeat(EXE_NAME)) {
47 g_randomizer = std::make_shared<Randomizer>(g_witnessProc); 46 case ProcStatus::NotRunning:
48 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL); 47 // Shut down randomizer, wait for startup
49 SetTimer(g_hwnd, CHECK_NEWGAME, 1000, NULL); // Start checking for new game 48 if (g_randomizer) g_randomizer = nullptr;
50 } 49 break;
51 break; 50 case ProcStatus::Running:
52 case CHECK_NEWGAME: 51 if (!g_randomizer) {
53 if (g_witnessProc) { 52 g_randomizer = std::make_shared<Randomizer>(g_witnessProc);
54 // It shouldn't be possible to pause earlier than this, so subsequent checks will fail. 53 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL);
55 if (g_witnessProc->GetCurrentFrame() < 80) { // New game 54 }
55 break;
56 case ProcStatus::NewGame: // This status will fire only once per new game
56 SetWindowText(g_seed, L""); 57 SetWindowText(g_seed, L"");
57 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL); 58 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL);
59 break;
58 } 60 }
59 SetTimer(g_hwnd, CHECK_NEWGAME, 1000, NULL); // Continue checking for new game
60 }
61 break; 61 break;
62 case RANDOMIZE_READY: 62 case RANDOMIZE_READY:
63 SetWindowText(g_randomizerStatus, L"Randomize"); 63 SetWindowText(g_randomizerStatus, L"Randomize");
@@ -65,6 +65,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
65 break; 65 break;
66 case RANDOMIZING: 66 case RANDOMIZING:
67 if (!g_randomizer) break; 67 if (!g_randomizer) break;
68 EnableWindow(g_randomizerStatus, FALSE);
68 SetWindowText(g_randomizerStatus, L"Randomizing..."); 69 SetWindowText(g_randomizerStatus, L"Randomizing...");
69 std::thread([]{ 70 std::thread([]{
70 g_randomizer->Randomize(); 71 g_randomizer->Randomize();
@@ -74,8 +75,6 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
74 case RANDOMIZE_DONE: 75 case RANDOMIZE_DONE:
75 SetWindowText(g_randomizerStatus, L"Randomized!"); 76 SetWindowText(g_randomizerStatus, L"Randomized!");
76 break; 77 break;
77 default:
78 break;
79 } 78 }
80 } 79 }
81 return DefWindowProc(hwnd, message, wParam, lParam); 80 return DefWindowProc(hwnd, message, wParam, lParam);
@@ -127,9 +126,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
127 126
128 CreateLabel(390, 15, 90, L"Version: " VERSION_STR); 127 CreateLabel(390, 15, 90, L"Version: " VERSION_STR);
129 g_seed = CreateText(10, 10, 100); 128 g_seed = CreateText(10, 10, 100);
130 g_randomizerStatus = CreateButton(120, 10, 100, L"Randomize", RANDOMIZING); 129 g_randomizerStatus = CreateButton(120, 10, 110, L"Randomize", RANDOMIZING);
131 EnableWindow(g_randomizerStatus, FALSE); 130 EnableWindow(g_randomizerStatus, FALSE);
132 PostMessage(g_hwnd, WM_COMMAND, PROC_ATTACH, NULL); 131 PostMessage(g_hwnd, WM_COMMAND, HEARTBEAT, NULL);
133 132
134 ShowWindow(g_hwnd, nCmdShow); 133 ShowWindow(g_hwnd, nCmdShow);
135 UpdateWindow(g_hwnd); 134 UpdateWindow(g_hwnd);
diff --git a/Source/Memory.cpp b/Source/Memory.cpp index d7f0212..b0e2e9d 100644 --- a/Source/Memory.cpp +++ b/Source/Memory.cpp
@@ -7,9 +7,6 @@
7#undef PROCESSENTRY32 7#undef PROCESSENTRY32
8#undef Process32Next 8#undef Process32Next
9 9
10Memory::Memory() {
11}
12
13[[nodiscard]] 10[[nodiscard]]
14bool Memory::Initialize(const std::wstring& processName) { 11bool Memory::Initialize(const std::wstring& processName) {
15 // First, get the handle of the process 12 // First, get the handle of the process
@@ -48,23 +45,40 @@ bool Memory::Initialize(const std::wstring& processName) {
48 return true; 45 return true;
49} 46}
50 47
51Memory::~Memory() { 48ProcStatus Memory::Heartbeat(const std::wstring& processName) {
52 if (_handle != nullptr) { 49 if (!_handle && !Initialize(processName)) {
53 CloseHandle(_handle); 50 // Couldn't initialize, definitely not running
51 return ProcStatus::NotRunning;
52 }
53
54 DWORD exitCode = 0;
55 GetExitCodeProcess(_handle, &exitCode);
56 if (exitCode != STILL_ACTIVE) {
57 // Process has exited, clean up.
58 _computedAddresses.clear();
59 _handle = NULL;
60 return ProcStatus::NotRunning;
54 } 61 }
55}
56 62
57int Memory::GetCurrentFrame() { 63 int currentFrame = 0x7FFFFFFF;
58 int SCRIPT_FRAMES;
59 if (GLOBALS == 0x5B28C0) { 64 if (GLOBALS == 0x5B28C0) {
60 SCRIPT_FRAMES = 0x5BE3B0; 65 currentFrame = ReadData<int>({0x5BE3B0}, 1)[0];
61 } else if (GLOBALS == 0x62D0A0) { 66 } else if (GLOBALS == 0x62D0A0) {
62 SCRIPT_FRAMES = 0x63954C; 67 currentFrame = ReadData<int>({0x63954C}, 1)[0];
63 } else { 68 } else {
64 assert(false); 69 assert(false);
65 return 0x7FFFFFFF;
66 } 70 }
67 return ReadData<int>({SCRIPT_FRAMES}, 1)[0]; 71 if (currentFrame < 80) return ProcStatus::NewGame;
72
73 // TODO: Some way to return ProcStatus::Randomized vs ProcStatus::NotRandomized vs ProcStatus::DeRandomized;
74
75 return ProcStatus::Running;
76}
77
78Memory::~Memory() {
79 if (_handle != nullptr) {
80 CloseHandle(_handle);
81 }
68} 82}
69 83
70void Memory::AddSigScan(const std::vector<byte>& scanBytes, const std::function<void(int index)>& scanFunc) 84void Memory::AddSigScan(const std::vector<byte>& scanBytes, const std::function<void(int index)>& scanFunc)
diff --git a/Source/Memory.h b/Source/Memory.h index f70de6a..d7552c5 100644 --- a/Source/Memory.h +++ b/Source/Memory.h
@@ -7,21 +7,25 @@
7// #define GLOBALS 0x5B28C0 7// #define GLOBALS 0x5B28C0
8#define GLOBALS 0x62D0A0 8#define GLOBALS 0x62D0A0
9 9
10enum class ProcStatus {
11 NotRunning,
12 Running,
13 NewGame
14};
15
10// https://github.com/erayarslan/WriteProcessMemory-Example 16// https://github.com/erayarslan/WriteProcessMemory-Example
11// http://stackoverflow.com/q/32798185 17// http://stackoverflow.com/q/32798185
12// http://stackoverflow.com/q/36018838 18// http://stackoverflow.com/q/36018838
13// http://stackoverflow.com/q/1387064 19// http://stackoverflow.com/q/1387064
14class Memory { 20class Memory {
15public: 21public:
16 Memory(); 22 Memory() = default;
17 bool Initialize(const std::wstring& processName); 23 ProcStatus Heartbeat(const std::wstring& processName);
18 ~Memory(); 24 ~Memory();
19 25
20 Memory(const Memory& memory) = delete; 26 Memory(const Memory& memory) = delete;
21 Memory& operator=(const Memory& other) = delete; 27 Memory& operator=(const Memory& other) = delete;
22 28
23 int GetCurrentFrame();
24
25 template <class T> 29 template <class T>
26 std::vector<T> ReadArray(int panel, int offset, int size) { 30 std::vector<T> ReadArray(int panel, int offset, int size) {
27 return ReadData<T>({GLOBALS, 0x18, panel*8, offset, 0}, size); 31 return ReadData<T>({GLOBALS, 0x18, panel*8, offset, 0}, size);
@@ -48,9 +52,6 @@ public:
48private: 52private:
49 template<class T> 53 template<class T>
50 std::vector<T> ReadData(const std::vector<int>& offsets, size_t numItems) { 54 std::vector<T> ReadData(const std::vector<int>& offsets, size_t numItems) {
51 if (GetExitCodeProcess(_process) != STILL_ACTIVE) {
52 // Signal error, somehow
53 }
54 std::vector<T> data; 55 std::vector<T> data;
55 data.resize(numItems); 56 data.resize(numItems);
56 for (int i=0; i<5; i++) { 57 for (int i=0; i<5; i++) {
@@ -73,8 +74,8 @@ private:
73 ThrowError(); 74 ThrowError();
74 } 75 }
75 76
77 bool Initialize(const std::wstring& processName);
76 void ThrowError(); 78 void ThrowError();
77
78 void* ComputeOffset(std::vector<int> offsets); 79 void* ComputeOffset(std::vector<int> offsets);
79 80
80 std::map<uintptr_t, uintptr_t> _computedAddresses; 81 std::map<uintptr_t, uintptr_t> _computedAddresses;