Skip to content

Instantly share code, notes, and snippets.

@dextercd
Last active December 29, 2022 01:57
Show Gist options
  • Save dextercd/23ce29b0bfaba20fd0f3e841def98bf8 to your computer and use it in GitHub Desktop.
Save dextercd/23ce29b0bfaba20fd0f3e841def98bf8 to your computer and use it in GitHub Desktop.
BlueAmulet's PhysBodySetTransform body function
#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