lazily find construct and remove ptrs without noita patcher

This commit is contained in:
bgkillas 2025-07-08 17:18:54 -04:00
parent d7d3e4ac31
commit 9dd156bc41
5 changed files with 216 additions and 17 deletions

157
blob_guy/Cargo.lock generated
View file

@ -92,8 +92,8 @@ dependencies = [
"hashbrown",
"paste",
"static_assertions",
"windows",
"windows-core",
"windows 0.58.0",
"windows-core 0.58.0",
]
[[package]]
@ -486,10 +486,12 @@ dependencies = [
"eframe",
"eyre",
"noita_api",
"object",
"rayon",
"rupl",
"rustc-hash 2.1.1",
"smallvec",
"windows 0.61.3",
]
[[package]]
@ -2182,6 +2184,17 @@ dependencies = [
"objc2-foundation 0.2.2",
]
[[package]]
name = "object"
version = "0.37.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a"
dependencies = [
"flate2",
"memchr",
"ruzstd",
]
[[package]]
name = "once_cell"
version = "1.21.3"
@ -2551,6 +2564,15 @@ version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "ruzstd"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3640bec8aad418d7d03c72ea2de10d5c646a598f9883c7babc160d91e3c1b26c"
dependencies = [
"twox-hash",
]
[[package]]
name = "ryu"
version = "1.0.20"
@ -2997,6 +3019,12 @@ version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
[[package]]
name = "twox-hash"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b907da542cbced5261bd3256de1b3a1bf340a3d37f93425a07362a1d687de56"
[[package]]
name = "type-map"
version = "0.5.1"
@ -3405,7 +3433,7 @@ dependencies = [
"wasm-bindgen",
"web-sys",
"wgpu-types",
"windows",
"windows 0.58.0",
]
[[package]]
@ -3457,23 +3485,69 @@ version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
dependencies = [
"windows-core",
"windows-core 0.58.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.61.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
dependencies = [
"windows-collections",
"windows-core 0.61.2",
"windows-future",
"windows-link",
"windows-numerics",
]
[[package]]
name = "windows-collections"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
dependencies = [
"windows-core 0.61.2",
]
[[package]]
name = "windows-core"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [
"windows-implement",
"windows-interface",
"windows-result",
"windows-strings",
"windows-implement 0.58.0",
"windows-interface 0.58.0",
"windows-result 0.2.0",
"windows-strings 0.1.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
"windows-implement 0.60.0",
"windows-interface 0.59.1",
"windows-link",
"windows-result 0.3.4",
"windows-strings 0.4.2",
]
[[package]]
name = "windows-future"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
dependencies = [
"windows-core 0.61.2",
"windows-link",
"windows-threading",
]
[[package]]
name = "windows-implement"
version = "0.58.0"
@ -3485,6 +3559,17 @@ dependencies = [
"syn",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.58.0"
@ -3496,6 +3581,33 @@ dependencies = [
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-numerics"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
"windows-core 0.61.2",
"windows-link",
]
[[package]]
name = "windows-result"
version = "0.2.0"
@ -3505,16 +3617,34 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [
"windows-result",
"windows-result 0.2.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-strings"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
@ -3613,6 +3743,15 @@ dependencies = [
"windows_x86_64_msvc 0.53.0",
]
[[package]]
name = "windows-threading"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
dependencies = [
"windows-link",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"

View file

@ -17,12 +17,18 @@ codegen-units=1
opt-level = 3
overflow-checks = true
[features]
default = ["data"]
data = ["dep:object","dep:windows"]
[dependencies]
noita_api = {path = "../noita_api"}
eyre = "0.6.12"
smallvec = "1.15.1"
rustc-hash = "2.1.1"
rayon = "1.10.0"
object = {version="0.37.1", optional = true}
windows = {version="0.61.3", features = ["Win32", "Win32_System", "Win32_System_LibraryLoader"], optional = true}
[dev-dependencies]
rupl = {git = "https://github.com/bgkillas/rupl.git", default-features = false, features = ["egui"] }

View file

@ -35,14 +35,11 @@ function OnWorldInitialized()
local grid_world = world_ffi.get_grid_world()
grid_world = tonumber(ffi.cast("intptr_t", grid_world))
local material_list = tonumber(ffi.cast("intptr_t", world_ffi.get_material_ptr(0)))
local world_info = np.GetWorldInfo()
local construct_cell = tonumber(ffi.cast("intptr_t", world_info.construct_cell))
local remove_cell = tonumber(ffi.cast("intptr_t", world_info.remove_cell))
local mat_len = 0
local name = CellFactory_GetName(mat_len)
while name ~= "unknown" do
mat_len = mat_len + 1
name = CellFactory_GetName(mat_len)
end
blob_guy.init_particle_world_state(grid_world, material_list, mat_len, construct_cell, remove_cell)
blob_guy.init_particle_world_state(grid_world, material_list, mat_len)
end

53
blob_guy/src/init_data.rs Normal file
View file

@ -0,0 +1,53 @@
use eyre::ContextCompat;
use object::{Object, ObjectSection};
use std::ffi::c_void;
use std::fs::File;
use std::io::Read;
use windows::Win32::System::LibraryLoader::GetModuleHandleA;
pub fn get_functions() -> eyre::Result<(*const c_void, *const c_void)> {
let exe = std::env::current_exe()?;
let mut file = File::open(exe)?;
let mut vec = Vec::with_capacity(15460864);
file.read_to_end(&mut vec)?;
let obj = object::File::parse(vec.as_slice())?;
let text = obj.section_by_name(".text").wrap_err("obj err")?;
let data = text.data()?;
let construct: &[u8] = &[0x8b, 0x46, 0x38, 0x33, 0xc9, 0x83, 0xf8, 0x01];
let remove: &[u8] = &[
0x8b, 0x06, 0x8b, 0xce, 0xff, 0x90, 0x9c, 0x00, 0x00, 0x00, 0x8b, 0x06, 0x8b, 0xce, 0x6a,
0x01, 0xff, 0x10,
];
let start = get_module();
let text_start = find_pattern(vec.as_slice(), data)?;
let construct = find_pattern(data, construct)?;
let remove = find_pattern(data, remove)?;
let construct_ptr = get_function_start(unsafe { start.add(2968 + text_start + construct) })?;
let remove_ptr = get_function_start(unsafe { start.add(2968 + text_start + remove) })?;
Ok((construct_ptr, remove_ptr))
}
fn find_pattern(data: &[u8], pattern: &[u8]) -> eyre::Result<usize> {
data.windows(pattern.len())
.position(|window| window == pattern)
.wrap_err("match err")
}
fn get_module() -> *const c_void {
unsafe { GetModuleHandleA(None).unwrap().0 }
}
fn get_function_start(func: *const c_void) -> eyre::Result<*const c_void> {
let mut it = func.cast::<u8>();
loop {
unsafe {
if it as isize % 16 == 0
&& (it.offset(-1).read() == 0xcc
|| it.offset(-1).read() == 0xc3
|| it.offset(-3).read() == 0xc2)
&& (it.read() >= 0x50 && it.read() < 0x58)
&& ((it.offset(1).read() >= 0x50 && it.offset(1).read() < 0x58)
|| (it.offset(1).read() == 0x8b && it.offset(2).read() == 0xec))
{
return Ok(it.cast::<c_void>());
}
}
it = unsafe { it.offset(-1) }
}
}

View file

@ -1,5 +1,7 @@
pub mod blob_guy;
pub mod chunk;
#[cfg(feature = "data")]
pub mod init_data;
pub mod noita;
use crate::blob_guy::Blob;
use crate::chunk::Chunk;
@ -10,7 +12,7 @@ use noita_api::lua::LuaState;
use noita_api::lua::lua_bindings::{LUA_REGISTRYINDEX, lua_State};
use smallvec::SmallVec;
use std::cell::RefCell;
use std::ffi::{c_int, c_void};
use std::ffi::c_int;
use std::mem::MaybeUninit;
pub const CHUNK_SIZE: usize = 128;
pub const CHUNK_AMOUNT: usize = 3;
@ -48,15 +50,17 @@ pub unsafe extern "C" fn luaopen_blob_guy(lua: *mut lua_State) -> c_int {
}
fn init_particle_world_state(lua: LuaState) -> eyre::Result<()> {
STATE.with(|state| {
let mut state = state.borrow_mut();
let mut state = state.try_borrow_mut()?;
#[cfg(feature = "data")]
let (construct_ptr, remove_ptr) = crate::init_data::get_functions()?;
#[cfg(not(feature = "data"))]
let (construct_ptr, remove_ptr): (_, _) = Default::default();
let world_ptr = lua.to_integer(1) as *const noita::ntypes::GridWorld;
let chunk_map = unsafe { world_ptr.as_ref().unwrap() }.chunk_map.cell_array;
let material_list_ptr = lua.to_integer(2) as *const noita::ntypes::CellData;
let mat_len = lua.to_integer(3);
let material_list =
unsafe { std::slice::from_raw_parts(material_list_ptr, mat_len as usize) };
let construct_ptr = lua.to_integer(4) as *const c_void;
let remove_ptr = lua.to_integer(5) as *const c_void;
let blob_guy = noita_api::raw::cell_factory_get_type("blob_guy".into())? as u16;
state.blob_guy = blob_guy;
let pws = ParticleWorldState {