Noita heap stuff

This commit is contained in:
IQuant 2025-10-12 15:41:45 +03:00
parent ea6a17323a
commit 43dcabe601
8 changed files with 79 additions and 28 deletions

View file

@ -1,6 +1,7 @@
use crate::blob_guy::OFFSET; use crate::blob_guy::OFFSET;
use crate::{CHUNK_AMOUNT, CHUNK_SIZE}; use crate::{CHUNK_AMOUNT, CHUNK_SIZE};
use eyre::{ContextCompat, eyre}; use eyre::{ContextCompat, eyre};
use noita_api::heap;
use noita_api::noita::types; use noita_api::noita::types;
use noita_api::noita::world::ParticleWorldState; use noita_api::noita::world::ParticleWorldState;
use rayon::iter::{ use rayon::iter::{
@ -228,7 +229,7 @@ impl ChunkOps for ParticleWorldState {
let world_x = x + i; let world_x = x + i;
let world_y = y + j; let world_y = y + j;
let cell = pixel_array.get_mut_raw(shift_x + i, shift_y + j); let cell = pixel_array.get_mut_raw(shift_x + i, shift_y + j);
let new = Box::leak(blob_cell.clone()); let new = heap::place_new_ref(*blob_cell.clone());
new.x = world_x; new.x = world_x;
new.y = world_y; new.y = world_y;
*cell = (new as *mut types::LiquidCell).cast(); *cell = (new as *mut types::LiquidCell).cast();

View file

@ -1,6 +1,7 @@
use crate::modules::{Module, ModuleCtx}; use crate::modules::{Module, ModuleCtx};
use crate::{WorldSync, my_peer_id}; use crate::{WorldSync, my_peer_id};
use eyre::{ContextCompat, eyre}; use eyre::{ContextCompat, eyre};
use noita_api::heap;
use noita_api::noita::types::{CellType, FireCell, GasCell, LiquidCell, Vec2i}; use noita_api::noita::types::{CellType, FireCell, GasCell, LiquidCell, Vec2i};
use noita_api::noita::world::ParticleWorldState; use noita_api::noita::world::ParticleWorldState;
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
@ -134,29 +135,27 @@ impl WorldData for ParticleWorldState {
*cell = ptr::null_mut(); *cell = ptr::null_mut();
} }
CellType::Liquid => { CellType::Liquid => {
let liquid = Box::leak(Box::new(unsafe { let mut liquid = unsafe {
LiquidCell::create(mat, self.cell_vtables.liquid(), self.world_ptr) LiquidCell::create(mat, self.cell_vtables.liquid(), self.world_ptr)
})); };
liquid.x = xs; liquid.x = xs;
liquid.y = ys; liquid.y = ys;
*cell = (liquid as *mut LiquidCell).cast(); *cell = heap::place_new(liquid).cast();
} }
CellType::Gas => { CellType::Gas => {
let gas = Box::leak(Box::new(unsafe { let mut gas =
GasCell::create(mat, self.cell_vtables.gas(), self.world_ptr) unsafe { GasCell::create(mat, self.cell_vtables.gas(), self.world_ptr) };
}));
gas.x = xs; gas.x = xs;
gas.y = ys; gas.y = ys;
*cell = (gas as *mut GasCell).cast(); *cell = heap::place_new(gas).cast();
} }
CellType::Solid => {} CellType::Solid => {}
CellType::Fire => { CellType::Fire => {
let fire = Box::leak(Box::new(unsafe { let mut fire =
FireCell::create(mat, self.cell_vtables.fire(), self.world_ptr) unsafe { FireCell::create(mat, self.cell_vtables.fire(), self.world_ptr) };
}));
fire.x = xs; fire.x = xs;
fire.y = ys; fire.y = ys;
*cell = (fire as *mut FireCell).cast(); *cell = heap::place_new(fire).cast();
} }
} }
} }
@ -232,14 +231,14 @@ pub fn test_world() {
celldata.material_type = rand::random::<u8>() as isize; celldata.material_type = rand::random::<u8>() as isize;
list[i] = celldata.material_type; list[i] = celldata.material_type;
let cell = Cell::create( let cell = Cell::create(
Box::leak(Box::new(celldata)), heap::place_new_ref(celldata),
CellVTable { CellVTable {
none: &NoneCellVTable { none: &NoneCellVTable {
unknown: [ptr::null_mut(); 41], unknown: [ptr::null_mut(); 41],
}, },
}, },
); );
*d = Box::leak(Box::new(cell)); *d = heap::place_new(cell);
} }
let chunk = Chunk { let chunk = Chunk {
data: unsafe { std::mem::transmute::<&mut _, &'static mut _>(&mut data) }, data: unsafe { std::mem::transmute::<&mut _, &'static mut _>(&mut data) },
@ -254,14 +253,14 @@ pub fn test_world() {
for d in data.iter_mut() { for d in data.iter_mut() {
let celldata = CellData::default(); let celldata = CellData::default();
let cell = Cell::create( let cell = Cell::create(
Box::leak(Box::new(celldata)), heap::place_new_ref(celldata),
CellVTable { CellVTable {
none: &NoneCellVTable { none: &NoneCellVTable {
unknown: [ptr::null_mut(); 41], unknown: [ptr::null_mut(); 41],
}, },
}, },
); );
*d = Box::leak(Box::new(cell)); *d = heap::place_new_ref(cell);
} }
let chunk = Chunk { let chunk = Chunk {
data: unsafe { std::mem::transmute::<&mut _, &'static mut _>(&mut data) }, data: unsafe { std::mem::transmute::<&mut _, &'static mut _>(&mut data) },

43
noita_api/src/heap.rs Normal file
View file

@ -0,0 +1,43 @@
use std::sync::LazyLock;
struct Msvcr {
op_new: unsafe extern "C" fn(n: std::os::raw::c_uint) -> *mut std::os::raw::c_void,
// op_delete: unsafe extern "C" fn(*const std::os::raw::c_void),
// op_delete_array: unsafe extern "C" fn(*const std::os::raw::c_void),
}
static MSVCR: LazyLock<Msvcr> = LazyLock::new(|| unsafe {
println!("Loading MSVCR");
let lib = libloading::Library::new("./msvcr120.dll").expect("library to exist");
let op_new = *lib.get(b"operator_new\0").expect("symbol to exist");
// let op_delete = *lib.get(b"operator_delete\0").expect("symbol to exist");
// let op_delete_array = *lib.get(b"operator_delete[]\0").expect("symbol to exist");
println!("Load OK");
Msvcr {
op_new,
// op_delete,
// op_delete_array,
}
});
/// Allocate some memory, using the same allocator noita uses.
pub fn raw_new(size: usize) -> *mut std::os::raw::c_void {
let size = size as std::os::raw::c_uint;
assert!(size > 0, "Doesn't make sense to allocate memory of size 0");
unsafe { (MSVCR.op_new)(size) }
}
/// Allocates memory using noita's allocator and moves *value* to it.
pub fn place_new<T>(value: T) -> *mut T {
let size = size_of::<T>();
let place = raw_new(size) as *mut T;
unsafe {
place.copy_from_nonoverlapping(&value, size);
}
place
}
/// Same as place_new, but returns &'static mut
pub fn place_new_ref<T>(value: T) -> &'static mut T {
unsafe { &mut *place_new(value) }
}

View file

@ -17,6 +17,7 @@ pub mod lua;
pub mod serialize; pub mod serialize;
pub use noita_api_macro::add_lua_fn; pub use noita_api_macro::add_lua_fn;
pub mod addr_grabber; pub mod addr_grabber;
pub mod heap;
pub mod noita; pub mod noita;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -18,6 +18,8 @@ use std::fmt::{Debug, Display, Formatter};
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::{alloc, ptr, slice}; use std::{alloc, ptr, slice};
pub use world::*; pub use world::*;
use crate::heap;
#[repr(C)] #[repr(C)]
union Buffer { union Buffer {
buffer: *const u8, buffer: *const u8,
@ -71,8 +73,8 @@ impl From<&str> for StdString {
size: value.len(), size: value.len(),
}; };
if res.capacity > 16 { if res.capacity > 16 {
let buffer = Box::leak(Box::new(value)); let buffer = heap::place_new(value);
res.buffer.buffer = buffer.as_ptr(); res.buffer.buffer = buffer.cast();
} else { } else {
let mut iter = value.as_bytes().iter(); let mut iter = value.as_bytes().iter();
res.buffer.sso_buffer = std::array::from_fn(|_| iter.next().copied().unwrap_or(0)) res.buffer.sso_buffer = std::array::from_fn(|_| iter.next().copied().unwrap_or(0))
@ -157,8 +159,8 @@ pub struct CString(pub *const u8);
impl From<&str> for CString { impl From<&str> for CString {
fn from(value: &str) -> Self { fn from(value: &str) -> Self {
let value = value.to_owned() + "\0"; let value = value.to_owned() + "\0";
let str = Box::leak(Box::new(value)); let str = heap::place_new(value).cast();
CString(str.as_ptr()) CString(str)
} }
} }
impl CString { impl CString {
@ -472,7 +474,7 @@ pub struct StdMap<K: 'static, V: 'static> {
impl<K: Default + 'static, V: Default + 'static> Default for StdMap<K, V> { impl<K: Default + 'static, V: Default + 'static> Default for StdMap<K, V> {
fn default() -> Self { fn default() -> Self {
Self { Self {
root: Box::leak(Box::new(StdMapNode::default())), root: unsafe { &mut *heap::place_new(StdMapNode::default()) },
len: 0, len: 0,
} }
} }
@ -520,7 +522,7 @@ impl<K: 'static, V: 'static> StdMap<K, V> {
if self.is_empty() { if self.is_empty() {
self.len += 1; self.len += 1;
let node = StdMapNode::new(key, value); let node = StdMapNode::new(key, value);
self.root.parent = Box::leak(Box::new(node)) as *mut _; self.root.parent = heap::place_new(node);
None None
} else { } else {
todo!() todo!()

View file

@ -1,5 +1,8 @@
use crate::noita::types::{ use crate::{
heap,
noita::types::{
BitSet, CString, Component, Entity, EntityManager, StdMap, StdString, StdVec, TagManager, BitSet, CString, Component, Entity, EntityManager, StdMap, StdString, StdVec, TagManager,
},
}; };
use std::ptr; use std::ptr;
#[repr(C)] #[repr(C)]
@ -141,7 +144,7 @@ impl ComponentBuffer {
unk3: StdVec::null(), unk3: StdVec::null(),
unk4: 0, unk4: 0,
}); });
let com = Box::leak(Box::new(com)); let com = heap::place_new(com);
let index = self.component_list.len(); let index = self.component_list.len();
self.component_list.push((com as *mut C).cast()); self.component_list.push((com as *mut C).cast());
if self.entities.len() > index { if self.entities.len() > index {
@ -184,7 +187,7 @@ impl ComponentBuffer {
} }
self.next[off] = self.end; self.next[off] = self.end;
} }
com unsafe { &mut *com }
} }
pub fn iter_components(&self, entry: usize) -> ComponentIter { pub fn iter_components(&self, entry: usize) -> ComponentIter {
if let Some(off) = self.entity_entry.get(entry) { if let Some(off) = self.entity_entry.get(entry) {

View file

@ -1,3 +1,4 @@
use crate::heap;
use crate::noita::types::component::{ComponentBuffer, ComponentData}; use crate::noita::types::component::{ComponentBuffer, ComponentData};
use crate::noita::types::{ use crate::noita::types::{
Component, ComponentTypeManager, Inventory2Component, StdMap, StdString, StdVec, Vec2, Component, ComponentTypeManager, Inventory2Component, StdMap, StdString, StdVec, Vec2,
@ -20,7 +21,7 @@ impl EntityManager {
children: std::ptr::null_mut(), children: std::ptr::null_mut(),
parent: std::ptr::null_mut(), parent: std::ptr::null_mut(),
}; };
let ent = Box::leak(Box::new(ent)); let ent = heap::place_new_ref(ent);
if let Some(entry) = self.free_ids.pop() { if let Some(entry) = self.free_ids.pop() {
ent.entry = entry; ent.entry = entry;
self.entities[entry] = ent; self.entities[entry] = ent;

View file

@ -1,3 +1,4 @@
use crate::heap;
use crate::noita::types::objects::{ConfigExplosion, ConfigGridCosmeticParticle}; use crate::noita::types::objects::{ConfigExplosion, ConfigGridCosmeticParticle};
use crate::noita::types::{StdMap, StdString, StdVec, ThiscallFn, Vec2, Vec2i}; use crate::noita::types::{StdMap, StdString, StdVec, ThiscallFn, Vec2, Vec2i};
use shared::world_sync::{Pixel, PixelFlags}; use shared::world_sync::{Pixel, PixelFlags};
@ -727,7 +728,7 @@ impl ChunkMap {
#[inline] #[inline]
pub fn insert(&mut self, x: isize, y: isize, chunk: Chunk) { pub fn insert(&mut self, x: isize, y: isize, chunk: Chunk) {
let index = (((y - 256) & 511) << 9) | ((x - 256) & 511); let index = (((y - 256) & 511) << 9) | ((x - 256) & 511);
self.chunk_array[index.cast_unsigned()] = Box::leak(Box::new(chunk)) self.chunk_array[index.cast_unsigned()] = heap::place_new(chunk)
} }
} }