This repository has been archived by the owner on Jul 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
109 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#include <Windows.h> | ||
|
||
#include <vector> | ||
|
||
// Types | ||
|
||
typedef void(__thiscall* onplaytest_t)(void*, void*); | ||
typedef void(__thiscall* cctouches_t)(void*, void*, void*); | ||
|
||
// Globals | ||
|
||
static bool g_hasPushStacked = 0; | ||
static onplaytest_t g_onPlaytest = nullptr; | ||
static cctouches_t g_onTouchBegan = nullptr; | ||
static cctouches_t g_onTouchEnded = nullptr; | ||
|
||
// Helpers | ||
|
||
static bool writeMemory( | ||
std::uintptr_t const address, | ||
std::vector<std::uint8_t> const& bytes) | ||
{ | ||
DWORD p; | ||
VirtualProtect(reinterpret_cast<LPVOID>(address), bytes.size(), PAGE_EXECUTE_READWRITE, &p); | ||
|
||
return ::WriteProcessMemory( | ||
::GetCurrentProcess(), | ||
reinterpret_cast<LPVOID>(address), | ||
bytes.data(), | ||
bytes.size(), | ||
NULL) == TRUE; | ||
} | ||
|
||
static bool writePtr( | ||
std::uintptr_t const address, | ||
std::uintptr_t const ptr) | ||
{ | ||
auto const p = reinterpret_cast<std::uint8_t const*>(&ptr); | ||
|
||
return ::writeMemory( | ||
address, | ||
std::vector<std::uint8_t>(p, p + sizeof(std::uintptr_t))); | ||
} | ||
|
||
// Callback | ||
|
||
static void __fastcall onplaytestHook(void* self, void* edx, void* param) | ||
{ | ||
if (!g_hasPushStacked) | ||
g_onPlaytest(self, param); | ||
} | ||
|
||
static void __fastcall ontouchbeganHook(void* self, void* edx, void* param1, void* param2) | ||
{ | ||
g_hasPushStacked = true; | ||
g_onTouchBegan(self, param1, param2); | ||
} | ||
|
||
static void __fastcall ontouchendedHook(void* self, void* edx, void* param1, void* param2) | ||
{ | ||
g_hasPushStacked = false; | ||
g_onTouchEnded(self, param1, param2); | ||
} | ||
|
||
// Main | ||
|
||
DWORD WINAPI MainThread(LPVOID) | ||
{ | ||
auto base = reinterpret_cast<std::uintptr_t>(GetModuleHandleA(NULL)); | ||
|
||
g_onPlaytest = reinterpret_cast<onplaytest_t>(base + 0x87600); | ||
g_onTouchBegan = reinterpret_cast<cctouches_t>(base + 0x907B0); | ||
g_onTouchEnded = reinterpret_cast<cctouches_t>(base + 0x911A0); | ||
|
||
auto const onPlaytestAddr1 = base + 0x76E53; | ||
auto const onPlaytestAddr2 = base + 0x92109; | ||
|
||
writePtr(onPlaytestAddr1 + 1, reinterpret_cast<std::uintptr_t>(&onplaytestHook)); | ||
writePtr(onPlaytestAddr2 + 1, reinterpret_cast<std::uintptr_t>(&onplaytestHook) - onPlaytestAddr2 - 5); | ||
writePtr(base + 0x2997D0, reinterpret_cast<std::uintptr_t>(&ontouchbeganHook)); | ||
writePtr(base + 0x2997D8, reinterpret_cast<std::uintptr_t>(&ontouchendedHook)); | ||
} | ||
|
||
// Entrypoint | ||
|
||
BOOL WINAPI DllMain(HINSTANCE dll, DWORD const reason, LPVOID) | ||
{ | ||
DisableThreadLibraryCalls(dll); | ||
|
||
if (reason == DLL_PROCESS_ATTACH) | ||
CreateThread(0, 0, &MainThread, 0, 0, 0); | ||
|
||
return TRUE; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# editorFreezeFix | ||
|
||
### The problem | ||
|
||
When using the editor, creators might accidentally hit the playtest key when placing objects: since the action of clicking is used by both normal mode and playtest mode, this causes a race condition where the editor switches to playtest mode (`EditorUI->0x1A4->0x3AC`) before the action of placing the object occurs. The state of the editor is then inconsistent, because it thinks we're constantly placing an object, and we cannot place more. | ||
|
||
![](Dasm.png) | ||
|
||
### The fix | ||
|
||
The fix is very simple: we check for the user click action, and we prevent the editor from entering playtest mode if the action is not done (for experts: if `ccTouchEnded()` is not done yet). | ||
|
||
### Credits | ||
|
||
Huge thanks to [night](https://twitter.com/uwunight_), who has asked me to fix this bug in the first place, and who told me a consistent way of reproducing it! |