mirror of
https://github.com/IntQuant/noita_entangled_worlds.git
synced 2025-10-19 07:03:16 +00:00
WIP attempt at a better make_ephemerial (currently it just crashes the game tho)
This commit is contained in:
parent
d7ca6fc099
commit
62f32a4863
4 changed files with 68 additions and 14 deletions
|
@ -1,12 +1,16 @@
|
||||||
use std::{
|
use std::{
|
||||||
cell::{LazyCell, RefCell},
|
cell::{LazyCell, RefCell},
|
||||||
ffi::{c_int, c_void},
|
ffi::{c_int, c_void},
|
||||||
|
mem,
|
||||||
sync::LazyLock,
|
sync::LazyLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
use iced_x86::Mnemonic;
|
use iced_x86::Mnemonic;
|
||||||
use lua_bindings::{lua_State, Lua51, LUA_GLOBALSINDEX};
|
use lua_bindings::{lua_State, Lua51, LUA_GLOBALSINDEX};
|
||||||
use noita::{NoitaPixelRun, ParticleWorldState};
|
use noita::{
|
||||||
|
ntypes::{Entity, EntityManager},
|
||||||
|
NoitaPixelRun, ParticleWorldState,
|
||||||
|
};
|
||||||
|
|
||||||
mod lua_bindings;
|
mod lua_bindings;
|
||||||
|
|
||||||
|
@ -29,14 +33,17 @@ thread_local! {
|
||||||
struct SavedWorldState {
|
struct SavedWorldState {
|
||||||
game_global: usize,
|
game_global: usize,
|
||||||
world_state_entity: usize,
|
world_state_entity: usize,
|
||||||
world_state_related: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GrabbedGlobals {
|
struct GrabbedGlobals {
|
||||||
// These 3 actually point to a pointer.
|
// These 3 actually point to a pointer.
|
||||||
game_global: *mut usize,
|
game_global: *mut usize,
|
||||||
world_state_entity: *mut usize,
|
world_state_entity: *mut usize,
|
||||||
world_state_related: *mut usize,
|
entity_manager: *mut EntityManager,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GrabbedFns {
|
||||||
|
get_entity: unsafe extern "C" fn(*const EntityManager, u32) -> *mut Entity,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -44,6 +51,7 @@ struct ExtState {
|
||||||
particle_world_state: Option<ParticleWorldState>,
|
particle_world_state: Option<ParticleWorldState>,
|
||||||
globals: Option<GrabbedGlobals>,
|
globals: Option<GrabbedGlobals>,
|
||||||
saved_world_state: Option<SavedWorldState>,
|
saved_world_state: Option<SavedWorldState>,
|
||||||
|
fns: Option<GrabbedFns>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// const EWEXT: [(&'static str, Function); 1] = [("testfn", None)];
|
// const EWEXT: [(&'static str, Function); 1] = [("testfn", None)];
|
||||||
|
@ -87,11 +95,10 @@ unsafe fn save_world_state() {
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
let game_global = state.globals.as_ref().unwrap().game_global.read();
|
let game_global = state.globals.as_ref().unwrap().game_global.read();
|
||||||
let world_state_entity = state.globals.as_ref().unwrap().world_state_entity.read();
|
let world_state_entity = state.globals.as_ref().unwrap().world_state_entity.read();
|
||||||
let world_state_related = state.globals.as_ref().unwrap().world_state_related.read();
|
|
||||||
state.saved_world_state = Some(SavedWorldState {
|
state.saved_world_state = Some(SavedWorldState {
|
||||||
game_global,
|
game_global,
|
||||||
world_state_entity,
|
world_state_entity,
|
||||||
world_state_related,
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -106,9 +113,6 @@ unsafe fn load_world_state() {
|
||||||
globals
|
globals
|
||||||
.world_state_entity
|
.world_state_entity
|
||||||
.write(saved_ws.world_state_entity);
|
.write(saved_ws.world_state_entity);
|
||||||
globals
|
|
||||||
.world_state_related
|
|
||||||
.write(saved_ws.world_state_related);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,15 +158,47 @@ unsafe fn grab_addrs(lua: *mut lua_State) {
|
||||||
// Pop the last element.
|
// Pop the last element.
|
||||||
LUA.lua_settop(lua, -2);
|
LUA.lua_settop(lua, -2);
|
||||||
|
|
||||||
|
LUA.lua_getfield(lua, LUA_GLOBALSINDEX, c"EntityGetFilename".as_ptr());
|
||||||
|
let base = LUA.lua_tocfunction(lua, -1).unwrap() as *const c_void;
|
||||||
|
let get_entity = mem::transmute_copy(&addr_grabber::grab_addr_from_instruction(
|
||||||
|
base,
|
||||||
|
0x0079782b - 0x00797570,
|
||||||
|
Mnemonic::Call,
|
||||||
|
));
|
||||||
|
println!("get_entity addr: 0x{:x}", get_entity as usize);
|
||||||
|
let entity_manager =
|
||||||
|
addr_grabber::grab_addr_from_instruction(base, 0x00797821 - 0x00797570, Mnemonic::Mov)
|
||||||
|
.cast();
|
||||||
|
println!("entity_manager addr: 0x{:x}", entity_manager as usize);
|
||||||
|
// Pop the last element.
|
||||||
|
LUA.lua_settop(lua, -2);
|
||||||
|
|
||||||
STATE.with(|state| {
|
STATE.with(|state| {
|
||||||
state.borrow_mut().globals = Some(GrabbedGlobals {
|
state.borrow_mut().globals = Some(GrabbedGlobals {
|
||||||
game_global,
|
game_global,
|
||||||
world_state_entity,
|
world_state_entity,
|
||||||
world_state_related: (0x01202ff0 as *mut usize),
|
entity_manager,
|
||||||
});
|
});
|
||||||
|
state.borrow_mut().fns = Some(GrabbedFns { get_entity })
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn make_ephemereal(lua: *mut lua_State) -> c_int {
|
||||||
|
unsafe {
|
||||||
|
let entity_id = LUA.lua_tointeger(lua, 1) as u32;
|
||||||
|
println!("Making {} ephemerial", entity_id);
|
||||||
|
STATE.with(|state| {
|
||||||
|
let state = state.borrow();
|
||||||
|
let entity = dbg!((state.fns.as_ref().unwrap().get_entity)(
|
||||||
|
state.globals.as_ref().unwrap().entity_manager,
|
||||||
|
entity_id,
|
||||||
|
));
|
||||||
|
entity.cast::<c_void>().offset(0x8).cast::<u32>().write(0);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// Only gets called by lua when loading a module.
|
/// Only gets called by lua when loading a module.
|
||||||
|
@ -180,6 +216,8 @@ pub unsafe extern "C" fn luaopen_ewext0(lua: *mut lua_State) -> c_int {
|
||||||
LUA.lua_setfield(lua, -2, c"load_world_state".as_ptr());
|
LUA.lua_setfield(lua, -2, c"load_world_state".as_ptr());
|
||||||
LUA.lua_pushcclosure(lua, Some(save_world_state_lua), 0);
|
LUA.lua_pushcclosure(lua, Some(save_world_state_lua), 0);
|
||||||
LUA.lua_setfield(lua, -2, c"save_world_state".as_ptr());
|
LUA.lua_setfield(lua, -2, c"save_world_state".as_ptr());
|
||||||
|
LUA.lua_pushcclosure(lua, Some(make_ephemereal), 0);
|
||||||
|
LUA.lua_setfield(lua, -2, c"make_ephemerial".as_ptr());
|
||||||
}
|
}
|
||||||
println!("Initializing ewext - Ok");
|
println!("Initializing ewext - Ok");
|
||||||
1
|
1
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{ffi::c_void, mem};
|
use std::{ffi::c_void, mem};
|
||||||
|
|
||||||
mod ntypes;
|
pub(crate) mod ntypes;
|
||||||
|
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub(crate) struct NoitaPixelRun {
|
pub(crate) struct NoitaPixelRun {
|
||||||
|
@ -176,4 +176,4 @@ impl ParticleWorldState {
|
||||||
self.runner.clear();
|
self.runner.clear();
|
||||||
runs
|
runs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Type defs borrowed from NoitaPatcher.
|
// Type defs borrowed from NoitaPatcher.
|
||||||
|
|
||||||
use std::ffi::c_char;
|
use std::ffi::{c_char, c_void};
|
||||||
|
|
||||||
pub(crate) const CELLDATA_SIZE: isize = 0x290;
|
pub(crate) const CELLDATA_SIZE: isize = 0x290;
|
||||||
|
|
||||||
|
@ -65,3 +65,16 @@ impl Cell {
|
||||||
self.material_ptr
|
self.material_ptr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct Entity {
|
||||||
|
_unknown0: [u8; 8],
|
||||||
|
_filename_index: u32,
|
||||||
|
// More stuff, not that relevant currently.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct EntityManager {
|
||||||
|
_fld: c_void,
|
||||||
|
// Unknown
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
local ffi = require("ffi")
|
local ffi = require("ffi")
|
||||||
local world_ffi = require("noitapatcher.nsew.world_ffi")
|
local world_ffi = require("noitapatcher.nsew.world_ffi")
|
||||||
|
|
||||||
|
np.CrossCallAdd("make_ephemerial", ewext.make_ephemerial)
|
||||||
|
|
||||||
local initial_world_state_entity = nil
|
local initial_world_state_entity = nil
|
||||||
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
function module.on_world_initialized()
|
function module.on_world_initialized()
|
||||||
initial_world_state_entity = GameGetWorldStateEntity()
|
initial_world_state_entity = GameGetWorldStateEntity()
|
||||||
-- ewext.save_world_state()
|
ewext.save_world_state()
|
||||||
local grid_world = world_ffi.get_grid_world()
|
local grid_world = world_ffi.get_grid_world()
|
||||||
local chunk_map = grid_world.vtable.get_chunk_map(grid_world)
|
local chunk_map = grid_world.vtable.get_chunk_map(grid_world)
|
||||||
grid_world = tonumber(ffi.cast("intptr_t", grid_world))
|
grid_world = tonumber(ffi.cast("intptr_t", grid_world))
|
||||||
|
@ -23,8 +25,9 @@ end
|
||||||
function module.on_world_update()
|
function module.on_world_update()
|
||||||
if GameGetWorldStateEntity() ~= initial_world_state_entity then
|
if GameGetWorldStateEntity() ~= initial_world_state_entity then
|
||||||
GamePrint("Whoops WSE is different "..GameGetWorldStateEntity().." "..initial_world_state_entity)
|
GamePrint("Whoops WSE is different "..GameGetWorldStateEntity().." "..initial_world_state_entity)
|
||||||
|
ewext.make_ephemerial(GameGetWorldStateEntity())
|
||||||
-- EntityKill(GameGetWorldStateEntity())
|
-- EntityKill(GameGetWorldStateEntity())
|
||||||
-- ewext.load_world_state()
|
ewext.load_world_state()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue