summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorjbzdarkid <jbzdarkid@gmail.com>2019-11-24 12:28:53 -0800
committerjbzdarkid <jbzdarkid@gmail.com>2019-11-24 12:28:53 -0800
commit92084d06a5c87338cc988b5bc5868e617213e6b9 (patch)
tree314cbf8ee06821b9569a7b279bc39e2bf04abc87
parent6059a1d1b99186a28bcd3c60822bc8310724bfd4 (diff)
downloadwitness-tutorializer-92084d06a5c87338cc988b5bc5868e617213e6b9.tar.gz
witness-tutorializer-92084d06a5c87338cc988b5bc5868e617213e6b9.tar.bz2
witness-tutorializer-92084d06a5c87338cc988b5bc5868e617213e6b9.zip
Try/catch, and select seed
-rw-r--r--App/Main.cpp21
-rw-r--r--Source/Memory.cpp34
-rw-r--r--Source/Memory.h36
-rw-r--r--Source/MemoryException.h53
-rw-r--r--Source/PuzzleSerializer.cpp120
-rw-r--r--Source/Randomizer.cpp35
-rw-r--r--Source/Randomizer2.cpp8
-rw-r--r--Source/Randomizer2.h6
-rw-r--r--Source/Source.vcxproj1
-rw-r--r--Test/Test.vcxproj4
10 files changed, 180 insertions, 138 deletions
diff --git a/App/Main.cpp b/App/Main.cpp index edf0898..9e2757e 100644 --- a/App/Main.cpp +++ b/App/Main.cpp
@@ -12,7 +12,7 @@
12#include "Randomizer.h" 12#include "Randomizer.h"
13#include "Randomizer2.h" 13#include "Randomizer2.h"
14 14
15// Heartbeat is defined to 0x401 by Memory.h 15#define HEARTBEAT 0x401
16#define RANDOMIZE_READY 0x402 16#define RANDOMIZE_READY 0x402
17#define RANDOMIZING 0403 17#define RANDOMIZING 0403
18#define RANDOMIZE_DONE 0x404 18#define RANDOMIZE_DONE 0x404
@@ -100,18 +100,18 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
100 SetRandomSeed(); 100 SetRandomSeed();
101 std::thread([]{ 101 std::thread([]{
102 if (IsDlgButtonChecked(g_hwnd, DISABLE_SNIPES)) { 102 if (IsDlgButtonChecked(g_hwnd, DISABLE_SNIPES)) {
103 g_randomizer->PreventSnipes(); 103 MEMORY_CATCH(g_randomizer->PreventSnipes());
104 } 104 }
105 if (IsDlgButtonChecked(g_hwnd, SPEED_UP_AUTOSCROLLERS)) { 105 if (IsDlgButtonChecked(g_hwnd, SPEED_UP_AUTOSCROLLERS)) {
106 g_randomizer->AdjustSpeed(); 106 MEMORY_CATCH(g_randomizer->AdjustSpeed());
107 } 107 }
108 if (IsDlgButtonChecked(g_hwnd, CHALLENGE_ONLY)) { 108 if (IsDlgButtonChecked(g_hwnd, CHALLENGE_ONLY)) {
109 SetWindowText(g_randomizerStatus, L"Randomizing Challenge..."); 109 SetWindowText(g_randomizerStatus, L"Randomizing Challenge...");
110 g_randomizer->RandomizeChallenge(); 110 MEMORY_CATCH(g_randomizer->RandomizeChallenge());
111 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_CHALLENGE_DONE, NULL); 111 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_CHALLENGE_DONE, NULL);
112 } else { 112 } else {
113 SetWindowText(g_randomizerStatus, L"Randomizing..."); 113 SetWindowText(g_randomizerStatus, L"Randomizing...");
114 g_randomizer->Randomize(); 114 MEMORY_CATCH(g_randomizer->Randomize());
115 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_DONE, NULL); 115 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_DONE, NULL);
116 } 116 }
117 }).detach(); 117 }).detach();
@@ -194,8 +194,13 @@ void SetRandomSeed() {
194 Random::SetSeed(_wtoi(text.c_str())); 194 Random::SetSeed(_wtoi(text.c_str()));
195 } else { // Random seed 195 } else { // Random seed
196 int seed = Random::RandInt(0, 999999); 196 int seed = Random::RandInt(0, 999999);
197 SetWindowText(g_seed, std::to_wstring(seed).c_str()); 197
198 RedrawWindow(g_seed, NULL, NULL, RDW_UPDATENOW); 198 text = std::to_wstring(seed);
199 SetWindowText(g_seed, text.c_str());
200 CHARRANGE range = {0, static_cast<long>(text.length())};
201 PostMessage(g_seed, EM_EXSETSEL, NULL, (LPARAM)&range);
202 SetFocus(g_seed);
203
199 Random::SetSeed(seed); 204 Random::SetSeed(seed);
200 } 205 }
201} 206}
@@ -275,7 +280,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
275 CreateButton(200, 220, 100, L"Randomize2", TMP4); 280 CreateButton(200, 220, 100, L"Randomize2", TMP4);
276#endif 281#endif
277 282
278 g_witnessProc->StartHeartbeat(g_hwnd); 283 g_witnessProc->StartHeartbeat(g_hwnd, HEARTBEAT);
279 284
280 ShowWindow(g_hwnd, nCmdShow); 285 ShowWindow(g_hwnd, nCmdShow);
281 UpdateWindow(g_hwnd); 286 UpdateWindow(g_hwnd);
diff --git a/Source/Memory.cpp b/Source/Memory.cpp index 55ef18a..80cd103 100644 --- a/Source/Memory.cpp +++ b/Source/Memory.cpp
@@ -22,22 +22,22 @@ Memory::~Memory() {
22 } 22 }
23} 23}
24 24
25void Memory::StartHeartbeat(HWND window, std::chrono::milliseconds beat) { 25void Memory::StartHeartbeat(HWND window, WPARAM wParam, std::chrono::milliseconds beat) {
26 if (_threadActive) return; 26 if (_threadActive) return;
27 _threadActive = true; 27 _threadActive = true;
28 _thread = std::thread([sharedThis = shared_from_this(), window, beat]{ 28 _thread = std::thread([sharedThis = shared_from_this(), window, wParam, beat]{
29 while (sharedThis->_threadActive) { 29 while (sharedThis->_threadActive) {
30 sharedThis->Heartbeat(window); 30 sharedThis->Heartbeat(window, wParam);
31 std::this_thread::sleep_for(beat); 31 std::this_thread::sleep_for(beat);
32 } 32 }
33 }); 33 });
34 _thread.detach(); 34 _thread.detach();
35} 35}
36 36
37void Memory::Heartbeat(HWND window) { 37void Memory::Heartbeat(HWND window, WPARAM wParam) {
38 if (!_handle && !Initialize()) { 38 if (!_handle && !Initialize()) {
39 // Couldn't initialize, definitely not running 39 // Couldn't initialize, definitely not running
40 PostMessage(window, WM_COMMAND, HEARTBEAT, (LPARAM)ProcStatus::NotRunning); 40 PostMessage(window, WM_COMMAND, wParam, (LPARAM)ProcStatus::NotRunning);
41 return; 41 return;
42 } 42 }
43 43
@@ -48,7 +48,7 @@ void Memory::Heartbeat(HWND window) {
48 // Process has exited, clean up. 48 // Process has exited, clean up.
49 _computedAddresses.clear(); 49 _computedAddresses.clear();
50 _handle = NULL; 50 _handle = NULL;
51 PostMessage(window, WM_COMMAND, HEARTBEAT, (LPARAM)ProcStatus::NotRunning); 51 PostMessage(window, WM_COMMAND, wParam, (LPARAM)ProcStatus::NotRunning);
52 return; 52 return;
53 } 53 }
54 54
@@ -62,13 +62,13 @@ void Memory::Heartbeat(HWND window) {
62 if (frameDelta < 0 && currentFrame < 250) { 62 if (frameDelta < 0 && currentFrame < 250) {
63 // Some addresses (e.g. Entity Manager) may get re-allocated on newgame. 63 // Some addresses (e.g. Entity Manager) may get re-allocated on newgame.
64 _computedAddresses.clear(); 64 _computedAddresses.clear();
65 PostMessage(window, WM_COMMAND, HEARTBEAT, (LPARAM)ProcStatus::NewGame); 65 PostMessage(window, WM_COMMAND, wParam, (LPARAM)ProcStatus::NewGame);
66 return; 66 return;
67 } 67 }
68 68
69 // TODO: Some way to return ProcStatus::Randomized vs ProcStatus::NotRandomized vs ProcStatus::DeRandomized; 69 // TODO: Some way to return ProcStatus::Randomized vs ProcStatus::NotRandomized vs ProcStatus::DeRandomized;
70 70
71 PostMessage(window, WM_COMMAND, HEARTBEAT, (LPARAM)ProcStatus::Running); 71 PostMessage(window, WM_COMMAND, wParam, (LPARAM)ProcStatus::Running);
72} 72}
73 73
74[[nodiscard]] 74[[nodiscard]]
@@ -151,16 +151,6 @@ int Memory::ExecuteSigScans()
151 return notFound; 151 return notFound;
152} 152}
153 153
154void Memory::ThrowError() {
155 std::wstring message(256, '\0');
156 DWORD error = GetLastError();
157 int length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, error, 1024, &message[0], static_cast<DWORD>(message.size()), nullptr);
158 message.resize(length);
159#ifndef NDEBUG
160 MessageBox(NULL, message.c_str(), L"Please tell darkid about this", MB_OK);
161#endif
162}
163
164void* Memory::ComputeOffset(std::vector<int> offsets) { 154void* Memory::ComputeOffset(std::vector<int> offsets) {
165 // Leave off the last offset, since it will be either read/write, and may not be of type uintptr_t. 155 // Leave off the last offset, since it will be either read/write, and may not be of type uintptr_t.
166 int final_offset = offsets.back(); 156 int final_offset = offsets.back();
@@ -177,11 +167,11 @@ void* Memory::ComputeOffset(std::vector<int> offsets) {
177#endif 167#endif
178 // If the address is not yet computed, then compute it. 168 // If the address is not yet computed, then compute it.
179 uintptr_t computedAddress = 0; 169 uintptr_t computedAddress = 0;
180 if (bool result = !ReadProcessMemory(_handle, reinterpret_cast<LPVOID>(cumulativeAddress), &computedAddress, sizeof(uintptr_t), NULL)) { 170 if (!ReadProcessMemory(_handle, reinterpret_cast<LPVOID>(cumulativeAddress), &computedAddress, sizeof(uintptr_t), NULL)) {
181 ThrowError(); 171 MEMORY_THROW("Couldn't compute offset.", offsets);
182 } 172 }
183 if (computedAddress == 0) { // Attempting to dereference a nullptr 173 if (computedAddress == 0) {
184 ThrowError(); 174 MEMORY_THROW("Attempted to derefence NULL while computing offsets.", offsets);
185 } 175 }
186 _computedAddresses[cumulativeAddress] = computedAddress; 176 _computedAddresses[cumulativeAddress] = computedAddress;
187#ifdef NDEBUG 177#ifdef NDEBUG
diff --git a/Source/Memory.h b/Source/Memory.h index 5332cc3..803a5f1 100644 --- a/Source/Memory.h +++ b/Source/Memory.h
@@ -4,11 +4,12 @@
4#include <thread> 4#include <thread>
5#include <vector> 5#include <vector>
6#include <windows.h> 6#include <windows.h>
7#include <cassert>
8#include "MemoryException.h"
7 9
8// #define GLOBALS 0x5B28C0 10// #define GLOBALS 0x5B28C0
9#define GLOBALS 0x62D0A0 11#define GLOBALS 0x62D0A0
10 12
11#define HEARTBEAT 0x401
12enum class ProcStatus { 13enum class ProcStatus {
13 NotRunning, 14 NotRunning,
14 Running, 15 Running,
@@ -24,7 +25,7 @@ class Memory final : public std::enable_shared_from_this<Memory> {
24public: 25public:
25 Memory(const std::wstring& processName); 26 Memory(const std::wstring& processName);
26 ~Memory(); 27 ~Memory();
27 void StartHeartbeat(HWND window, std::chrono::milliseconds beat = std::chrono::milliseconds(1000)); 28 void StartHeartbeat(HWND window, WPARAM wParam, std::chrono::milliseconds beat = std::chrono::milliseconds(1000));
28 29
29 Memory(const Memory& memory) = delete; 30 Memory(const Memory& memory) = delete;
30 Memory& operator=(const Memory& other) = delete; 31 Memory& operator=(const Memory& other) = delete;
@@ -63,40 +64,25 @@ public:
63private: 64private:
64 template<class T> 65 template<class T>
65 std::vector<T> ReadData(const std::vector<int>& offsets, size_t numItems) { 66 std::vector<T> ReadData(const std::vector<int>& offsets, size_t numItems) {
66 if (numItems == 0) return {}; 67 assert(numItems);
67 std::vector<T> data; 68 std::vector<T> data;
68 data.resize(numItems); 69 data.resize(numItems);
69 void* computedOffset = ComputeOffset(offsets); 70 if (!ReadProcessMemory(_handle, ComputeOffset(offsets), &data[0], sizeof(T) * numItems, nullptr)) {
70 for (int i=0; i<5; i++) { 71 MEMORY_THROW("Failed to read data.", offsets, numItems);
71 if (ReadProcessMemory(_handle, computedOffset, &data[0], sizeof(T) * numItems, nullptr)) {
72 if (i != 0) {
73 int k = 0;
74 }
75 return data;
76 }
77 } 72 }
78 ThrowError(); 73 return data;
79 return {};
80 } 74 }
81 75
82 template <class T> 76 template <class T>
83 void WriteData(const std::vector<int>& offsets, const std::vector<T>& data) { 77 void WriteData(const std::vector<int>& offsets, const std::vector<T>& data) {
84 if (data.empty()) return; 78 assert(data.size());
85 void* computedOffset = ComputeOffset(offsets); 79 if (!WriteProcessMemory(_handle, ComputeOffset(offsets), &data[0], sizeof(T) * data.size(), nullptr)) {
86 for (int i=0; i<5; i++) { 80 MEMORY_THROW("Failed to write data.", offsets, data.size());
87 if (WriteProcessMemory(_handle, computedOffset, &data[0], sizeof(T) * data.size(), nullptr)) {
88 if (i != 0) {
89 int k = 0;
90 }
91 return;
92 }
93 } 81 }
94 ThrowError();
95 } 82 }
96 83
97 void Heartbeat(HWND window); 84 void Heartbeat(HWND window, WPARAM wParam);
98 bool Initialize(); 85 bool Initialize();
99 void ThrowError();
100 void* ComputeOffset(std::vector<int> offsets); 86 void* ComputeOffset(std::vector<int> offsets);
101 87
102 int _previousFrame = 0; 88 int _previousFrame = 0;
diff --git a/Source/MemoryException.h b/Source/MemoryException.h new file mode 100644 index 0000000..ad2824d --- /dev/null +++ b/Source/MemoryException.h
@@ -0,0 +1,53 @@
1#pragma once
2#include <exception>
3#include <string>
4#include <vector>
5
6#define MEMORY_CATCH(expr) \
7try { \
8 (expr); \
9} catch (MemoryException exc) { \
10 MemoryException::HandleException(exc); \
11} \
12do {} while (0)
13
14#define MEMORY_THROW(...) throw MemoryException(__func__, __LINE__, ##__VA_ARGS__);
15
16class MemoryException : public std::exception {
17public:
18 inline MemoryException(const char* func, int32_t line, const char* message) noexcept
19 : MemoryException(func, line, message, {}, 0) {}
20 inline MemoryException(const char* func, int32_t line, const char* message, const std::vector<int>& offsets) noexcept
21 : MemoryException(func, line, message, offsets, 0) {}
22 inline MemoryException(const char* func, int32_t line, const char* message, const std::vector<int>& offsets, size_t numItems) noexcept
23 : _func(func), _line(line), _message(message), _offsets(offsets), _numItems(numItems) {}
24
25 ~MemoryException() = default;
26 inline const char* what() const noexcept {
27 return _message;
28 }
29 static void HandleException(const MemoryException& exc) noexcept {
30 std::string msg = "MemoryException thrown in function ";
31 msg += exc._func;
32 msg += " on line " + std::to_string(exc._line) + ":\n" + exc._message + "\nOffsets:";
33 for (int offset : exc._offsets) {
34 msg += " " + std::to_string(offset);
35 }
36 msg += "\n";
37 if (exc._numItems != 0) {
38 msg += "Num Items: " + std::to_string(exc._numItems) + "\n";
39 }
40 OutputDebugStringA(msg.c_str());
41#ifndef NDEBUG
42 MessageBoxA(NULL, msg.c_str(), "Memory Exception Thrown", MB_OK);
43#endif
44 }
45
46private:
47 const char* _func;
48 int32_t _line;
49 const char* _message;
50 const std::vector<int> _offsets;
51 size_t _numItems = 0;
52};
53
diff --git a/Source/PuzzleSerializer.cpp b/Source/PuzzleSerializer.cpp index fb4166b..3dffde1 100644 --- a/Source/PuzzleSerializer.cpp +++ b/Source/PuzzleSerializer.cpp
@@ -8,73 +8,81 @@
8PuzzleSerializer::PuzzleSerializer(const std::shared_ptr<Memory>& memory) : _memory(memory) {} 8PuzzleSerializer::PuzzleSerializer(const std::shared_ptr<Memory>& memory) : _memory(memory) {}
9 9
10Puzzle PuzzleSerializer::ReadPuzzle(int id) { 10Puzzle PuzzleSerializer::ReadPuzzle(int id) {
11 int width = _memory->ReadEntityData<int>(id, GRID_SIZE_X, 1)[0];
12 int height = _memory->ReadEntityData<int>(id, GRID_SIZE_Y, 1)[0];
13 if (width == 0) width = height;
14 if (height == 0) height = width;
15 if (width < 0 || height < 0) return Puzzle(); // @Error: Grid size should be always positive? Looks like the starting panels break this rule, though.
16
17 _numGridLocations = width * height; // Highest location which represents a gridded intersection
18 _numIntersections = _memory->ReadEntityData<int>(id, NUM_DOTS, 1)[0];
19 _intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, _numIntersections);
20 int numConnections = _memory->ReadEntityData<int>(id, NUM_CONNECTIONS, 1)[0];
21 _connectionsA = _memory->ReadArray<int>(id, DOT_CONNECTION_A, numConnections);
22 _connectionsB = _memory->ReadArray<int>(id, DOT_CONNECTION_B, numConnections);
23 _intersectionLocations = _memory->ReadArray<float>(id, DOT_POSITIONS, _numIntersections*2);
24
25 Puzzle p; 11 Puzzle p;
26 p.NewGrid(width - 1, height - 1); 12 try {
27 ReadIntersections(p); 13 int width = _memory->ReadEntityData<int>(id, GRID_SIZE_X, 1)[0];
28 ReadExtras(p); 14 int height = _memory->ReadEntityData<int>(id, GRID_SIZE_Y, 1)[0];
29 ReadDecorations(p, id); 15 if (width == 0) width = height;
30 ReadSequence(p, id); 16 if (height == 0) height = width;
31 ReadSymmetry(p, id); 17 if (width < 0 || height < 0) return Puzzle(); // @Error: Grid size should be always positive? Looks like the starting panels break this rule, though.
18
19 _numGridLocations = width * height; // Highest location which represents a gridded intersection
20 _numIntersections = _memory->ReadEntityData<int>(id, NUM_DOTS, 1)[0];
21 _intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, _numIntersections);
22 int numConnections = _memory->ReadEntityData<int>(id, NUM_CONNECTIONS, 1)[0];
23 _connectionsA = _memory->ReadArray<int>(id, DOT_CONNECTION_A, numConnections);
24 _connectionsB = _memory->ReadArray<int>(id, DOT_CONNECTION_B, numConnections);
25 _intersectionLocations = _memory->ReadArray<float>(id, DOT_POSITIONS, _numIntersections*2);
26
27 p.NewGrid(width - 1, height - 1);
28 ReadIntersections(p);
29 ReadExtras(p);
30 ReadDecorations(p, id);
31 ReadSequence(p, id);
32 ReadSymmetry(p, id);
33 } catch (MemoryException exc) {
34 MemoryException::HandleException(exc);
35 }
32 return p; 36 return p;
33} 37}
34 38
35void PuzzleSerializer::WritePuzzle(const Puzzle& p, int id) { 39void PuzzleSerializer::WritePuzzle(const Puzzle& p, int id) {
36 _intersectionFlags.clear(); 40 try {
37 _connectionsA.clear(); 41 _intersectionFlags.clear();
38 _connectionsB.clear(); 42 _connectionsA.clear();
39 _intersectionLocations.clear(); 43 _connectionsB.clear();
40 _extraLocations.clear(); 44 _intersectionLocations.clear();
41 45 _extraLocations.clear();
42 MIN = 0.1f; 46
43 MAX = 0.9f; 47 MIN = 0.1f;
44 WIDTH_INTERVAL = (MAX - MIN) / (p.width/2); 48 MAX = 0.9f;
45 HEIGHT_INTERVAL = (MAX - MIN) / (p.height/2); 49 WIDTH_INTERVAL = (MAX - MIN) / (p.width/2);
46 GAP_SIZE = min(WIDTH_INTERVAL, HEIGHT_INTERVAL) / 2; 50 HEIGHT_INTERVAL = (MAX - MIN) / (p.height/2);
47 // @Improvement: This will make grid cells square... but how do I keep the puzzle centered? Maybe save extra metadata? 51 GAP_SIZE = min(WIDTH_INTERVAL, HEIGHT_INTERVAL) / 2;
48 // INTERVAL = (MAX - MIN) / (max(p.width, p.height) / 2); 52 // @Improvement: This will make grid cells square... but how do I keep the puzzle centered? Maybe save extra metadata?
49 // GAP_SIZE = INTERVAL / 2; 53 // INTERVAL = (MAX - MIN) / (max(p.width, p.height) / 2);
54 // GAP_SIZE = INTERVAL / 2;
50 55
51 WriteIntersections(p); 56 WriteIntersections(p);
52 WriteEndpoints(p); 57 WriteEndpoints(p);
53 WriteDots(p); 58 WriteDots(p);
54 WriteGaps(p); 59 WriteGaps(p);
55 WriteDecorations(p, id); 60 WriteDecorations(p, id);
56 WriteSequence(p, id); 61 WriteSequence(p, id);
57 WriteSymmetry(p, id); 62 WriteSymmetry(p, id);
58 63
59#ifndef NDEBUG 64#ifndef NDEBUG
60 int maxDots = _memory->ReadEntityData<int>(id, NUM_DOTS, 1)[0]; 65 int maxDots = _memory->ReadEntityData<int>(id, NUM_DOTS, 1)[0];
61 assert(_intersectionFlags.size() <= maxDots); 66 assert(_intersectionFlags.size() <= maxDots);
62 assert(_intersectionLocations.size() <= maxDots*2); 67 assert(_intersectionLocations.size() <= maxDots*2);
63 68
64 int maxConnections = _memory->ReadEntityData<int>(id, NUM_CONNECTIONS, 1)[0]; 69 int maxConnections = _memory->ReadEntityData<int>(id, NUM_CONNECTIONS, 1)[0];
65 assert(_connectionsA.size() <= maxConnections); 70 assert(_connectionsA.size() <= maxConnections);
66 assert(_connectionsB.size() <= maxConnections); 71 assert(_connectionsB.size() <= maxConnections);
67#endif 72#endif
68 73
69 _memory->WriteEntityData<int>(id, GRID_SIZE_X, {(p.width + 1)/2}); 74 _memory->WriteEntityData<int>(id, GRID_SIZE_X, {(p.width + 1)/2});
70 _memory->WriteEntityData<int>(id, GRID_SIZE_Y, {(p.height + 1)/2}); 75 _memory->WriteEntityData<int>(id, GRID_SIZE_Y, {(p.height + 1)/2});
71 _memory->WriteEntityData<int>(id, NUM_DOTS, {static_cast<int>(_intersectionFlags.size())}); 76 _memory->WriteEntityData<int>(id, NUM_DOTS, {static_cast<int>(_intersectionFlags.size())});
72 _memory->WriteArray<float>(id, DOT_POSITIONS, _intersectionLocations); 77 _memory->WriteArray<float>(id, DOT_POSITIONS, _intersectionLocations);
73 _memory->WriteArray<int>(id, DOT_FLAGS, _intersectionFlags); 78 _memory->WriteArray<int>(id, DOT_FLAGS, _intersectionFlags);
74 _memory->WriteEntityData<int>(id, NUM_CONNECTIONS, {static_cast<int>(_connectionsA.size())}); 79 _memory->WriteEntityData<int>(id, NUM_CONNECTIONS, {static_cast<int>(_connectionsA.size())});
75 _memory->WriteArray<int>(id, DOT_CONNECTION_A, _connectionsA); 80 _memory->WriteArray<int>(id, DOT_CONNECTION_A, _connectionsA);
76 _memory->WriteArray<int>(id, DOT_CONNECTION_B, _connectionsB); 81 _memory->WriteArray<int>(id, DOT_CONNECTION_B, _connectionsB);
77 _memory->WriteEntityData<int>(id, NEEDS_REDRAW, {1}); 82 _memory->WriteEntityData<int>(id, NEEDS_REDRAW, {1});
83 } catch (MemoryException exc) {
84 MemoryException::HandleException(exc);
85 }
78} 86}
79 87
80void PuzzleSerializer::ReadIntersections(Puzzle& p) { 88void PuzzleSerializer::ReadIntersections(Puzzle& p) {
diff --git a/Source/Randomizer.cpp b/Source/Randomizer.cpp index 13f381a..1427f4d 100644 --- a/Source/Randomizer.cpp +++ b/Source/Randomizer.cpp
@@ -129,28 +129,28 @@ void Randomizer::Randomize() {
129 // Sig scans will be run during challenge randomization. 129 // Sig scans will be run during challenge randomization.
130 130
131 // Seed challenge first for future-proofing 131 // Seed challenge first for future-proofing
132 RandomizeChallenge(); 132 MEMORY_CATCH(RandomizeChallenge());
133 133
134 // Content swaps -- must happen before squarePanels 134 // Content swaps -- must happen before squarePanels
135 Randomize(upDownPanels, SWAP::LINES | SWAP::COLORS); 135 MEMORY_CATCH(Randomize(upDownPanels, SWAP::LINES | SWAP::COLORS));
136 Randomize(leftForwardRightPanels, SWAP::LINES | SWAP::COLORS); 136 MEMORY_CATCH(Randomize(leftForwardRightPanels, SWAP::LINES | SWAP::COLORS));
137 137
138 Randomize(squarePanels, SWAP::LINES | SWAP::COLORS); 138 MEMORY_CATCH(Randomize(squarePanels, SWAP::LINES | SWAP::COLORS));
139 139
140 // Individual area modifications 140 // Individual area modifications
141 RandomizeTutorial(); 141 MEMORY_CATCH(RandomizeTutorial());
142 RandomizeDesert(); 142 MEMORY_CATCH(RandomizeDesert());
143 RandomizeQuarry(); 143 MEMORY_CATCH(RandomizeQuarry());
144 RandomizeTreehouse(); 144 MEMORY_CATCH(RandomizeTreehouse());
145 RandomizeKeep(); 145 MEMORY_CATCH(RandomizeKeep());
146 RandomizeShadows(); 146 MEMORY_CATCH(RandomizeShadows());
147 RandomizeMonastery(); 147 MEMORY_CATCH(RandomizeMonastery());
148 RandomizeBunker(); 148 MEMORY_CATCH(RandomizeBunker());
149 RandomizeJungle(); 149 MEMORY_CATCH(RandomizeJungle());
150 RandomizeSwamp(); 150 MEMORY_CATCH(RandomizeSwamp());
151 RandomizeMountain(); 151 MEMORY_CATCH(RandomizeMountain());
152 RandomizeTown(); 152 MEMORY_CATCH(RandomizeTown());
153 RandomizeSymmetry(); 153 MEMORY_CATCH(RandomizeSymmetry());
154 // RandomizeAudioLogs(); 154 // RandomizeAudioLogs();
155} 155}
156 156
@@ -210,6 +210,7 @@ void Randomizer::RandomizeQuarry() {
210 210
211void Randomizer::RandomizeTreehouse() { 211void Randomizer::RandomizeTreehouse() {
212 // Ensure that whatever pivot panels we have are flagged as "pivotable" 212 // Ensure that whatever pivot panels we have are flagged as "pivotable"
213 // @Bug: Can return {}, be careful!
213 int panelFlags = _memory->ReadEntityData<int>(0x17DD1, STYLE_FLAGS, 1)[0]; 214 int panelFlags = _memory->ReadEntityData<int>(0x17DD1, STYLE_FLAGS, 1)[0];
214 _memory->WriteEntityData<int>(0x17DD1, STYLE_FLAGS, {panelFlags | 0x8000}); 215 _memory->WriteEntityData<int>(0x17DD1, STYLE_FLAGS, {panelFlags | 0x8000});
215 panelFlags = _memory->ReadEntityData<int>(0x17CE3, STYLE_FLAGS, 1)[0]; 216 panelFlags = _memory->ReadEntityData<int>(0x17CE3, STYLE_FLAGS, 1)[0];
diff --git a/Source/Randomizer2.cpp b/Source/Randomizer2.cpp index c823567..782e248 100644 --- a/Source/Randomizer2.cpp +++ b/Source/Randomizer2.cpp
@@ -1,5 +1,5 @@
1#include "Memory.h"
2#include "Randomizer2.h" 1#include "Randomizer2.h"
2#include "PuzzleSerializer.h"
3#include "Randomizer2Core.h" 3#include "Randomizer2Core.h"
4#include "Puzzle.h" 4#include "Puzzle.h"
5#include "Random.h" 5#include "Random.h"
@@ -10,7 +10,7 @@
10 10
11#pragma warning (disable: 26451) 11#pragma warning (disable: 26451)
12 12
13Randomizer2::Randomizer2(const std::shared_ptr<Memory>& memory) : _memory(memory), _serializer(PuzzleSerializer(_memory)) {} 13Randomizer2::Randomizer2(const PuzzleSerializer& serializer) : _serializer(serializer) {}
14 14
15void Randomizer2::Randomize() { 15void Randomizer2::Randomize() {
16 RandomizeTutorial(); 16 RandomizeTutorial();
@@ -361,9 +361,9 @@ void Randomizer2::SetGate(int panel, int X, int Y) {
361 } 361 }
362 362
363 SetPos(panel, x, y, 19.2f); 363 SetPos(panel, x, y, 19.2f);
364 _memory->WriteEntityData<float>(panel, ORIENTATION, {0.0f, 0.0f, z, w}); 364 // _memory->WriteEntityData<float>(panel, ORIENTATION, {0.0f, 0.0f, z, w});
365} 365}
366 366
367void Randomizer2::SetPos(int panel, float x, float y, float z) { 367void Randomizer2::SetPos(int panel, float x, float y, float z) {
368 _memory->WriteEntityData<float>(panel, POSITION, {x, y, z}); 368 // _memory->WriteEntityData<float>(panel, POSITION, {x, y, z});
369} \ No newline at end of file 369} \ No newline at end of file
diff --git a/Source/Randomizer2.h b/Source/Randomizer2.h index 47a9ebd..c8c3db5 100644 --- a/Source/Randomizer2.h +++ b/Source/Randomizer2.h
@@ -1,11 +1,10 @@
1#pragma once 1#pragma once
2#include <memory>
3#include "PuzzleSerializer.h" 2#include "PuzzleSerializer.h"
4 3
5class Memory; 4class Puzzle;
6class Randomizer2 { 5class Randomizer2 {
7public: 6public:
8 Randomizer2(const std::shared_ptr<Memory>& memory); 7 Randomizer2(const PuzzleSerializer& serializer);
9 void Randomize(); 8 void Randomize();
10 void RandomizeTutorial(); 9 void RandomizeTutorial();
11 void RandomizeSymmetry(); 10 void RandomizeSymmetry();
@@ -16,6 +15,5 @@ private:
16 void SetGate(int panel, int X, int Y); 15 void SetGate(int panel, int X, int Y);
17 void SetPos(int panel, float x, float y, float z); 16 void SetPos(int panel, float x, float y, float z);
18 17
19 std::shared_ptr<Memory> _memory;
20 PuzzleSerializer _serializer; 18 PuzzleSerializer _serializer;
21}; 19};
diff --git a/Source/Source.vcxproj b/Source/Source.vcxproj index 33e3697..5aaa0b0 100644 --- a/Source/Source.vcxproj +++ b/Source/Source.vcxproj
@@ -159,6 +159,7 @@
159 <ItemGroup> 159 <ItemGroup>
160 <ClInclude Include="ChallengeRandomizer.h" /> 160 <ClInclude Include="ChallengeRandomizer.h" />
161 <ClInclude Include="Memory.h" /> 161 <ClInclude Include="Memory.h" />
162 <ClInclude Include="MemoryException.h" />
162 <ClInclude Include="Puzzle.h" /> 163 <ClInclude Include="Puzzle.h" />
163 <ClInclude Include="Panels.h" /> 164 <ClInclude Include="Panels.h" />
164 <ClInclude Include="PuzzleSerializer.h" /> 165 <ClInclude Include="PuzzleSerializer.h" />
diff --git a/Test/Test.vcxproj b/Test/Test.vcxproj index 9023285..857cdd4 100644 --- a/Test/Test.vcxproj +++ b/Test/Test.vcxproj
@@ -67,7 +67,7 @@
67 <Link> 67 <Link>
68 <GenerateDebugInformation>true</GenerateDebugInformation> 68 <GenerateDebugInformation>true</GenerateDebugInformation>
69 <SubSystem>Console</SubSystem> 69 <SubSystem>Console</SubSystem>
70 <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> 70 <LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
71 </Link> 71 </Link>
72 </ItemDefinitionGroup> 72 </ItemDefinitionGroup>
73 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> 73 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -88,7 +88,7 @@
88 <Link> 88 <Link>
89 <GenerateDebugInformation>true</GenerateDebugInformation> 89 <GenerateDebugInformation>true</GenerateDebugInformation>
90 <SubSystem>Console</SubSystem> 90 <SubSystem>Console</SubSystem>
91 <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> 91 <LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
92 </Link> 92 </Link>
93 </ItemDefinitionGroup> 93 </ItemDefinitionGroup>
94 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 94 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">