Skip to content
This repository has been archived by the owner on Jul 5, 2023. It is now read-only.

Commit

Permalink
Upload
Browse files Browse the repository at this point in the history
  • Loading branch information
cos8oih committed Jun 17, 2021
1 parent a49b278 commit c806ef2
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
Binary file added Dasm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
94 changes: 94 additions & 0 deletions Main.cpp
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;
}
15 changes: 15 additions & 0 deletions README.md
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!

0 comments on commit c806ef2

Please sign in to comment.