mirror of
https://github.com/IntQuant/noita_entangled_worlds.git
synced 2025-10-19 07:03:16 +00:00
275 lines
11 KiB
Rust
275 lines
11 KiB
Rust
use std::{os::raw::c_void, ptr};
|
|
|
|
use crate::lua::LuaState;
|
|
use crate::noita::types::{
|
|
ComponentSystemManager, ComponentTypeManager, EntityManager, GameGlobal, GlobalStats,
|
|
Inventory, Mods, Platform, StdString, StdVec, TagManager, TranslationManager,
|
|
};
|
|
use iced_x86::{Decoder, DecoderOptions, Mnemonic};
|
|
|
|
pub(crate) unsafe fn grab_addr_from_instruction(
|
|
func: *const c_void,
|
|
offset: isize,
|
|
expected_mnemonic: Mnemonic,
|
|
) -> *mut c_void {
|
|
let instruction_addr = func.wrapping_offset(offset);
|
|
// We don't really have an idea of how many bytes the instruction takes, so just take *enough* bytes for most cases.
|
|
let instruction_bytes = unsafe { ptr::read_unaligned(instruction_addr.cast::<[u8; 16]>()) };
|
|
let mut decoder = Decoder::with_ip(
|
|
32,
|
|
&instruction_bytes,
|
|
instruction_addr as u64,
|
|
DecoderOptions::NONE,
|
|
);
|
|
let instruction = decoder.decode();
|
|
|
|
#[cfg(debug_assertions)]
|
|
if instruction.mnemonic() != expected_mnemonic {
|
|
println!("Encountered unexpected mnemonic: {instruction}");
|
|
}
|
|
assert_eq!(instruction.mnemonic(), expected_mnemonic);
|
|
|
|
instruction.memory_displacement32() as *mut c_void
|
|
}
|
|
|
|
// This only stores pointers that are constant, so should be safe to share between threads.
|
|
unsafe impl Sync for Globals {}
|
|
unsafe impl Send for Globals {}
|
|
|
|
#[derive(Debug)]
|
|
pub struct GlobalsRef {
|
|
pub world_seed: usize,
|
|
pub new_game_count: usize,
|
|
pub game_global: &'static GameGlobal,
|
|
pub entity_manager: &'static EntityManager,
|
|
pub entity_tag_manager: &'static TagManager<u16>,
|
|
pub component_type_manager: &'static ComponentTypeManager,
|
|
pub component_tag_manager: &'static TagManager<u8>,
|
|
pub translation_manager: &'static TranslationManager,
|
|
pub platform: &'static Platform,
|
|
pub global_stats: &'static GlobalStats,
|
|
pub filenames: &'static StdVec<StdString>,
|
|
pub inventory: &'static Inventory,
|
|
pub mods: &'static Mods,
|
|
pub max_component: &'static usize,
|
|
pub component_manager: &'static ComponentSystemManager,
|
|
}
|
|
#[derive(Debug)]
|
|
pub struct GlobalsMut {
|
|
pub world_seed: &'static mut usize,
|
|
pub new_game_count: &'static mut usize,
|
|
pub game_global: &'static mut GameGlobal,
|
|
pub entity_manager: &'static mut EntityManager,
|
|
pub entity_tag_manager: &'static mut TagManager<u16>,
|
|
pub component_type_manager: &'static mut ComponentTypeManager,
|
|
pub component_tag_manager: &'static mut TagManager<u8>,
|
|
pub translation_manager: &'static mut TranslationManager,
|
|
pub platform: &'static mut Platform,
|
|
pub global_stats: &'static mut GlobalStats,
|
|
pub filenames: &'static mut StdVec<StdString>,
|
|
pub inventory: &'static mut Inventory,
|
|
pub mods: &'static mut Mods,
|
|
pub max_component: &'static mut usize,
|
|
pub component_manager: &'static mut ComponentSystemManager,
|
|
}
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct Globals {
|
|
pub world_seed: *mut usize,
|
|
pub new_game_count: *mut usize,
|
|
pub game_global: *const *mut GameGlobal,
|
|
pub entity_manager: *const *mut EntityManager,
|
|
pub entity_tag_manager: *const *mut TagManager<u16>,
|
|
pub component_type_manager: *mut ComponentTypeManager,
|
|
pub component_tag_manager: *const *mut TagManager<u8>,
|
|
pub translation_manager: *mut TranslationManager,
|
|
pub platform: *mut Platform,
|
|
pub global_stats: *mut GlobalStats,
|
|
pub filenames: *mut StdVec<StdString>,
|
|
pub inventory: *mut Inventory,
|
|
pub mods: *mut Mods,
|
|
pub max_component: *mut usize,
|
|
pub component_manager: *mut ComponentSystemManager,
|
|
}
|
|
#[allow(clippy::mut_from_ref)]
|
|
impl Globals {
|
|
pub fn world_seed(&self) -> usize {
|
|
unsafe { self.world_seed.as_ref().copied().unwrap() }
|
|
}
|
|
pub fn new_game_count(&self) -> usize {
|
|
unsafe { self.new_game_count.as_ref().copied().unwrap() }
|
|
}
|
|
pub fn game_global(&self) -> &'static GameGlobal {
|
|
unsafe { self.game_global.as_ref().unwrap().as_ref().unwrap() }
|
|
}
|
|
pub fn entity_manager(&self) -> &'static EntityManager {
|
|
unsafe { self.entity_manager.as_ref().unwrap().as_ref().unwrap() }
|
|
}
|
|
pub fn entity_tag_manager(&self) -> &'static TagManager<u16> {
|
|
unsafe { self.entity_tag_manager.as_ref().unwrap().as_ref().unwrap() }
|
|
}
|
|
pub fn component_type_manager(&self) -> &'static ComponentTypeManager {
|
|
unsafe { self.component_type_manager.as_ref().unwrap() }
|
|
}
|
|
pub fn component_tag_manager(&self) -> &'static TagManager<u8> {
|
|
unsafe {
|
|
self.component_tag_manager
|
|
.as_ref()
|
|
.unwrap()
|
|
.as_ref()
|
|
.unwrap()
|
|
}
|
|
}
|
|
pub fn component_manager(&self) -> &'static ComponentSystemManager {
|
|
unsafe { self.component_manager.as_ref().unwrap() }
|
|
}
|
|
pub fn translation_manager(&self) -> &'static TranslationManager {
|
|
unsafe { self.translation_manager.as_ref().unwrap() }
|
|
}
|
|
pub fn platform(&self) -> &'static Platform {
|
|
unsafe { self.platform.as_ref().unwrap() }
|
|
}
|
|
pub fn global_stats(&self) -> &'static GlobalStats {
|
|
unsafe { self.global_stats.as_ref().unwrap() }
|
|
}
|
|
pub fn filenames(&self) -> &'static StdVec<StdString> {
|
|
unsafe { self.filenames.as_ref().unwrap() }
|
|
}
|
|
pub fn inventory(&self) -> &'static Inventory {
|
|
unsafe { self.inventory.as_ref().unwrap() }
|
|
}
|
|
pub fn mods(&self) -> &'static Mods {
|
|
unsafe { self.mods.as_ref().unwrap() }
|
|
}
|
|
pub fn max_component(&self) -> &'static usize {
|
|
unsafe { self.max_component.as_ref().unwrap() }
|
|
}
|
|
pub fn world_seed_mut(&self) -> &'static mut usize {
|
|
unsafe { self.world_seed.as_mut().unwrap() }
|
|
}
|
|
pub fn new_game_count_mut(&self) -> &'static mut usize {
|
|
unsafe { self.new_game_count.as_mut().unwrap() }
|
|
}
|
|
pub fn game_global_mut(&self) -> &'static mut GameGlobal {
|
|
unsafe { self.game_global.as_ref().unwrap().as_mut().unwrap() }
|
|
}
|
|
pub fn entity_manager_mut(&self) -> &'static mut EntityManager {
|
|
unsafe { self.entity_manager.as_ref().unwrap().as_mut().unwrap() }
|
|
}
|
|
pub fn entity_tag_manager_mut(&self) -> &'static mut TagManager<u16> {
|
|
unsafe { self.entity_tag_manager.as_ref().unwrap().as_mut().unwrap() }
|
|
}
|
|
pub fn component_type_manager_mut(&self) -> &'static mut ComponentTypeManager {
|
|
unsafe { self.component_type_manager.as_mut().unwrap() }
|
|
}
|
|
pub fn component_tag_manager_mut(&self) -> &'static mut TagManager<u8> {
|
|
unsafe {
|
|
self.component_tag_manager
|
|
.as_ref()
|
|
.unwrap()
|
|
.as_mut()
|
|
.unwrap()
|
|
}
|
|
}
|
|
pub fn translation_manager_mut(&self) -> &'static mut TranslationManager {
|
|
unsafe { self.translation_manager.as_mut().unwrap() }
|
|
}
|
|
pub fn platform_mut(&self) -> &'static mut Platform {
|
|
unsafe { self.platform.as_mut().unwrap() }
|
|
}
|
|
pub fn global_stats_mut(&self) -> &'static mut GlobalStats {
|
|
unsafe { self.global_stats.as_mut().unwrap() }
|
|
}
|
|
pub fn filenames_mut(&self) -> &'static mut StdVec<StdString> {
|
|
unsafe { self.filenames.as_mut().unwrap() }
|
|
}
|
|
pub fn inventory_mut(&self) -> &'static mut Inventory {
|
|
unsafe { self.inventory.as_mut().unwrap() }
|
|
}
|
|
pub fn mods_mut(&self) -> &'static mut Mods {
|
|
unsafe { self.mods.as_mut().unwrap() }
|
|
}
|
|
pub fn max_component_mut(&self) -> &'static mut usize {
|
|
unsafe { self.max_component.as_mut().unwrap() }
|
|
}
|
|
pub fn component_manager_mut(&self) -> &'static mut ComponentSystemManager {
|
|
unsafe { self.component_manager.as_mut().unwrap() }
|
|
}
|
|
pub fn as_ref(&self) -> GlobalsRef {
|
|
GlobalsRef {
|
|
world_seed: self.world_seed(),
|
|
new_game_count: self.new_game_count(),
|
|
game_global: self.game_global(),
|
|
entity_manager: self.entity_manager(),
|
|
entity_tag_manager: self.entity_tag_manager(),
|
|
component_type_manager: self.component_type_manager(),
|
|
component_tag_manager: self.component_tag_manager(),
|
|
translation_manager: self.translation_manager(),
|
|
platform: self.platform(),
|
|
global_stats: self.global_stats(),
|
|
filenames: self.filenames(),
|
|
inventory: self.inventory(),
|
|
mods: self.mods(),
|
|
max_component: self.max_component(),
|
|
component_manager: self.component_manager(),
|
|
}
|
|
}
|
|
pub fn as_mut(&self) -> GlobalsMut {
|
|
GlobalsMut {
|
|
world_seed: self.world_seed_mut(),
|
|
new_game_count: self.new_game_count_mut(),
|
|
game_global: self.game_global_mut(),
|
|
entity_manager: self.entity_manager_mut(),
|
|
entity_tag_manager: self.entity_tag_manager_mut(),
|
|
component_type_manager: self.component_type_manager_mut(),
|
|
component_tag_manager: self.component_tag_manager_mut(),
|
|
translation_manager: self.translation_manager_mut(),
|
|
platform: self.platform_mut(),
|
|
global_stats: self.global_stats_mut(),
|
|
filenames: self.filenames_mut(),
|
|
inventory: self.inventory_mut(),
|
|
mods: self.mods_mut(),
|
|
max_component: self.max_component_mut(),
|
|
component_manager: self.component_manager_mut(),
|
|
}
|
|
}
|
|
pub fn new(lua: LuaState) -> Self {
|
|
lua.get_global(c"EntityGetFilename");
|
|
let base = lua.to_cfunction(-1).unwrap() as *const c_void;
|
|
let entity_manager: *const *mut EntityManager = unsafe {
|
|
grab_addr_from_instruction(base, 0x00797821 - 0x00797570, Mnemonic::Mov).cast()
|
|
};
|
|
lua.pop_last();
|
|
let world_seed = 0x1205004 as *mut usize;
|
|
let new_game_count = 0x1205024 as *mut usize;
|
|
let global_stats = 0x1208940 as *mut GlobalStats;
|
|
let game_global = 0x122374c as *const *mut GameGlobal;
|
|
let entity_tag_manager = 0x1206fac as *const *mut TagManager<u16>;
|
|
let component_type_manager = 0x1223c88 as *mut ComponentTypeManager;
|
|
let component_tag_manager = 0x1204b30 as *const *mut TagManager<u8>;
|
|
let translation_manager = 0x1207c28 as *mut TranslationManager;
|
|
let platform = 0x1221bc0 as *mut Platform;
|
|
let filenames = 0x1207bd4 as *mut StdVec<StdString>;
|
|
let inventory = 0x12224f0 as *mut Inventory;
|
|
let mods = 0x1207e90 as *mut Mods;
|
|
let max_component = 0x1152ff0 as *mut usize;
|
|
let component_manager = 0x12236e8 as *mut ComponentSystemManager;
|
|
Self {
|
|
world_seed,
|
|
new_game_count,
|
|
game_global,
|
|
entity_manager,
|
|
entity_tag_manager,
|
|
component_type_manager,
|
|
component_tag_manager,
|
|
translation_manager,
|
|
platform,
|
|
global_stats,
|
|
filenames,
|
|
inventory,
|
|
mods,
|
|
max_component,
|
|
component_manager,
|
|
}
|
|
}
|
|
}
|