mirror of
https://github.com/IntQuant/noita_entangled_worlds.git
synced 2025-10-19 07:03:16 +00:00
Compare commits
4 commits
ea6a17323a
...
f3b3e81c01
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f3b3e81c01 | ||
![]() |
8d18843147 | ||
![]() |
7f0d7fbb53 | ||
![]() |
43dcabe601 |
10 changed files with 113 additions and 53 deletions
|
@ -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();
|
||||||
|
|
|
@ -8,6 +8,7 @@ use modules::{Module, ModuleCtx, entity_sync::EntitySync};
|
||||||
use net::NetManager;
|
use net::NetManager;
|
||||||
use noita_api::add_lua_fn;
|
use noita_api::add_lua_fn;
|
||||||
use noita_api::addr_grabber::Globals;
|
use noita_api::addr_grabber::Globals;
|
||||||
|
use noita_api::heap::raw_new;
|
||||||
use noita_api::noita::types::EntityManager;
|
use noita_api::noita::types::EntityManager;
|
||||||
use noita_api::noita::world::ParticleWorldState;
|
use noita_api::noita::world::ParticleWorldState;
|
||||||
use noita_api::{
|
use noita_api::{
|
||||||
|
@ -357,6 +358,7 @@ pub(crate) fn print_error(error: eyre::Report) -> eyre::Result<()> {
|
||||||
pub unsafe extern "C" fn luaopen_ewext(lua: *mut lua_State) -> c_int {
|
pub unsafe extern "C" fn luaopen_ewext(lua: *mut lua_State) -> c_int {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("Initializing ewext");
|
println!("Initializing ewext");
|
||||||
|
raw_new(1);
|
||||||
|
|
||||||
if let Err(_e) = KEEP_SELF_LOADED.as_ref() {
|
if let Err(_e) = KEEP_SELF_LOADED.as_ref() {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::{WorldSync, my_peer_id};
|
||||||
use eyre::{ContextCompat, eyre};
|
use eyre::{ContextCompat, eyre};
|
||||||
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 noita_api::{game_print, heap};
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
use shared::NoitaOutbound;
|
use shared::NoitaOutbound;
|
||||||
use shared::world_sync::{
|
use shared::world_sync::{
|
||||||
|
@ -98,13 +99,14 @@ impl WorldData for ParticleWorldState {
|
||||||
else {
|
else {
|
||||||
return Err(eyre!("chunk not loaded"));
|
return Err(eyre!("chunk not loaded"));
|
||||||
};
|
};
|
||||||
|
let mut chunk_iter = chunk.iter_mut();
|
||||||
let (shift_x, shift_y) = self.get_shift::<CHUNK_SIZE>(cx, cy);
|
let (shift_x, shift_y) = self.get_shift::<CHUNK_SIZE>(cx, cy);
|
||||||
for ((j, i), p) in (shift_x..shift_x + CHUNK_SIZE as isize)
|
for j in shift_y..shift_y + CHUNK_SIZE as isize {
|
||||||
.flat_map(|i| (shift_y..shift_y + CHUNK_SIZE as isize).map(move |j| (i, j)))
|
for i in shift_x..shift_x + CHUNK_SIZE as isize {
|
||||||
.zip(chunk.iter_mut())
|
*chunk_iter.next().unwrap() = pixel_array.get_pixel(i, j);
|
||||||
{
|
}
|
||||||
*p = pixel_array.get_pixel(i, j);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
unsafe fn decode_world(&self, chunk: NoitaWorldUpdate) -> eyre::Result<()> {
|
unsafe fn decode_world(&self, chunk: NoitaWorldUpdate) -> eyre::Result<()> {
|
||||||
|
@ -126,37 +128,39 @@ impl WorldData for ParticleWorldState {
|
||||||
let cell = pixel_array.get_mut_raw(shift_x + x, shift_y + y);
|
let cell = pixel_array.get_mut_raw(shift_x + x, shift_y + y);
|
||||||
let xs = start_x + x;
|
let xs = start_x + x;
|
||||||
let ys = start_y + y;
|
let ys = start_y + y;
|
||||||
let Some(mat) = self.material_list.get_static(pixel.mat() as usize) else {
|
if pixel.is_air() {
|
||||||
return Err(eyre!("mat does not exist"));
|
*cell = ptr::null_mut();
|
||||||
};
|
} else {
|
||||||
match mat.cell_type {
|
let Some(mat) = self.material_list.get_static(pixel.mat() as usize) else {
|
||||||
CellType::None => {
|
return Err(eyre!("mat does not exist"));
|
||||||
*cell = ptr::null_mut();
|
};
|
||||||
}
|
match mat.cell_type {
|
||||||
CellType::Liquid => {
|
CellType::None => {}
|
||||||
let liquid = Box::leak(Box::new(unsafe {
|
CellType::Liquid => {
|
||||||
LiquidCell::create(mat, self.cell_vtables.liquid(), self.world_ptr)
|
let mut liquid = unsafe {
|
||||||
}));
|
LiquidCell::create(mat, self.cell_vtables.liquid(), self.world_ptr)
|
||||||
liquid.x = xs;
|
};
|
||||||
liquid.y = ys;
|
liquid.x = xs;
|
||||||
*cell = (liquid as *mut LiquidCell).cast();
|
liquid.y = ys;
|
||||||
}
|
*cell = heap::place_new(liquid).cast();
|
||||||
CellType::Gas => {
|
}
|
||||||
let gas = Box::leak(Box::new(unsafe {
|
CellType::Gas => {
|
||||||
GasCell::create(mat, self.cell_vtables.gas(), self.world_ptr)
|
let mut gas = unsafe {
|
||||||
}));
|
GasCell::create(mat, self.cell_vtables.gas(), self.world_ptr)
|
||||||
gas.x = xs;
|
};
|
||||||
gas.y = ys;
|
gas.x = xs;
|
||||||
*cell = (gas as *mut GasCell).cast();
|
gas.y = ys;
|
||||||
}
|
*cell = heap::place_new(gas).cast();
|
||||||
CellType::Solid => {}
|
}
|
||||||
CellType::Fire => {
|
CellType::Solid => {}
|
||||||
let fire = Box::leak(Box::new(unsafe {
|
CellType::Fire => {
|
||||||
FireCell::create(mat, self.cell_vtables.fire(), self.world_ptr)
|
let mut fire = unsafe {
|
||||||
}));
|
FireCell::create(mat, self.cell_vtables.fire(), self.world_ptr)
|
||||||
fire.x = xs;
|
};
|
||||||
fire.y = ys;
|
fire.x = xs;
|
||||||
*cell = (fire as *mut FireCell).cast();
|
fire.y = ys;
|
||||||
|
*cell = heap::place_new(fire).cast();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,14 +236,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 +258,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) },
|
||||||
|
|
41
noita_api/src/heap.rs
Normal file
41
noita_api/src/heap.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
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 {
|
||||||
|
let lib = libloading::Library::new("./msvcr120.dll").expect("library to exist");
|
||||||
|
let op_new = *lib.get(b"??2@YAPAXI@Z\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");
|
||||||
|
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) }
|
||||||
|
}
|
|
@ -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)]
|
||||||
|
|
|
@ -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!()
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use crate::noita::types::{
|
use crate::{
|
||||||
BitSet, CString, Component, Entity, EntityManager, StdMap, StdString, StdVec, TagManager,
|
heap,
|
||||||
|
noita::types::{
|
||||||
|
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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,10 @@ impl Pixel {
|
||||||
pub fn flags(self) -> PixelFlags {
|
pub fn flags(self) -> PixelFlags {
|
||||||
unsafe { std::mem::transmute((self.0 >> 12) as u8) }
|
unsafe { std::mem::transmute((self.0 >> 12) as u8) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_air(&self) -> bool {
|
||||||
|
self.mat() == 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Encode, Decode, Clone)]
|
#[derive(Debug, Encode, Decode, Clone)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue