Last active
December 29, 2022 01:57
-
-
Save dextercd/23ce29b0bfaba20fd0f3e841def98bf8 to your computer and use it in GitHub Desktop.
BlueAmulet's PhysBodySetTransform body function
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
#include <algorithm> | |
#include <cstddef> | |
#include <cstdint> | |
#include <cstring> | |
#include <iterator> | |
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
#include <dbghelp.h> | |
extern "C" { | |
#include <lua.h> | |
#include <lauxlib.h> | |
} | |
namespace { | |
struct Node { | |
// std::map implementation detail | |
void* left; | |
void* parent; | |
void* right; | |
char color; | |
char isnil; | |
int component_id; | |
void* component_ptr; | |
}; | |
struct CompIt { | |
Node* ptr; | |
CompIt() {} | |
bool operator==(const CompIt& other) { return ptr == other.ptr; } | |
bool operator!=(const CompIt& other) { return !(*this == other); } | |
}; | |
typedef CompIt (__stdcall* fnkGetComponent)(const int&); | |
fnkGetComponent getComponent = nullptr; | |
const std::uint8_t get_comp_search[] = { | |
0x8b, 0xd6, 0x8b, 0x46, 0x04, 0x80, 0x78, 0x0d, 0x00, 0x75, 0x2b, 0x8b, 0x4d, 0x0c, 0x8b, 0x09, | |
0x8d, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x39, 0x48, 0x10, 0x73, 0x05, 0x8b, 0x40, 0x08, 0xeb, 0x04, | |
0x8b, 0xd0, 0x8b, 0x00, 0x80, 0x78, 0x0d, 0x00, 0x74, 0xec, 0x3b, 0xd6, 0x74, 0x08, 0x89, 0x55, | |
0x0c, 0x3b, 0x4a, 0x10, 0x73, 0x03, 0x89, 0x75, 0x0c, 0x8b, 0x45, 0x08, 0x8d, 0x4d, 0x0c, 0x8b, | |
0x09, 0x5e, 0x89, 0x08, 0x5d, 0xc2, 0x08, 0x00 | |
}; | |
const std::ptrdiff_t function_offset = -10; | |
fnkGetComponent find_get_component() | |
{ | |
void* exe_location = GetModuleHandleA(nullptr); | |
IMAGE_NT_HEADERS* header = ImageNtHeader(exe_location); | |
auto section_byte_start = (char*)&header->OptionalHeader + header->FileHeader.SizeOfOptionalHeader; | |
auto section_begin = (IMAGE_SECTION_HEADER*)section_byte_start; | |
auto section_end = section_begin + header->FileHeader.NumberOfSections; | |
auto text_section = std::find_if(section_begin, section_end, | |
[](IMAGE_SECTION_HEADER& section) { return std::strcmp((char*)section.Name, ".text") == 0; }); | |
auto text_start = (std::uint8_t*)exe_location + text_section->VirtualAddress; | |
auto text_end = text_start + text_section->SizeOfRawData; | |
// The Steam noita(_dev).exe files have two occurrences of the search text, | |
// for both of them it's the last occurrence that is the get component by id | |
// function. (That's why it's using std::find_end instead of std::search) | |
auto search_result = std::find_end( | |
text_start, text_end, | |
std::begin(get_comp_search), std::end(get_comp_search)); | |
if (search_result == text_end) | |
return nullptr; | |
return (fnkGetComponent)(search_result + function_offset); | |
} | |
} | |
// Check 8DE910 (b2Body::Dump()) for offsets | |
int PhysBodySetTransform(lua_State* L) { | |
if (getComponent == nullptr) { | |
getComponent = find_get_component(); | |
} | |
int componentId = luaL_checkinteger(L, 1); | |
double x = luaL_checknumber(L, 2); | |
double y = luaL_checknumber(L, 3); | |
double r = luaL_checknumber(L, 4); | |
double vx = luaL_checknumber(L, 5); | |
double vy = luaL_checknumber(L, 6); | |
double av = luaL_checknumber(L, 7); | |
CompIt comp_it = getComponent(componentId); | |
if (comp_it == getComponent(-943857)) { | |
return 0; | |
} | |
char* physBody = (char*)comp_it.ptr->component_ptr; | |
int b2Body = *(int*)(physBody + 0x48); | |
if (b2Body == 0) { | |
return 0; | |
} | |
*(double*)(b2Body + 0x58) = x; | |
*(double*)(b2Body + 0x60) = y; | |
*(double*)(b2Body + 0x70) = r; | |
*(double*)(b2Body + 0x80) = vx; | |
*(double*)(b2Body + 0x88) = vy; | |
*(double*)(b2Body + 0x90) = av; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment