Split noita api stuff into it's own crate

This commit is contained in:
IQuant 2024-11-25 17:44:56 +03:00
parent bac266e456
commit 66a5a009e2
11 changed files with 121 additions and 106 deletions

10
ewext/Cargo.lock generated
View file

@ -46,6 +46,7 @@ dependencies = [
"eyre", "eyre",
"iced-x86", "iced-x86",
"libloading", "libloading",
"noita_api",
"noita_api_macro", "noita_api_macro",
] ]
@ -129,6 +130,15 @@ dependencies = [
"adler2", "adler2",
] ]
[[package]]
name = "noita_api"
version = "0.1.0"
dependencies = [
"eyre",
"libloading",
"noita_api_macro",
]
[[package]] [[package]]
name = "noita_api_macro" name = "noita_api_macro"
version = "0.1.0" version = "0.1.0"

View file

@ -17,3 +17,4 @@ backtrace = "0.3.74"
iced-x86 = "1.21.0" iced-x86 = "1.21.0"
noita_api_macro = {path = "noita_api_macro"} noita_api_macro = {path = "noita_api_macro"}
eyre = "0.6.12" eyre = "0.6.12"
noita_api = {path = "noita_api"}

View file

@ -0,0 +1,9 @@
[package]
name = "noita_api"
version = "0.1.0"
edition = "2021"
[dependencies]
eyre = "0.6.12"
libloading = "0.8.5"
noita_api_macro = {path = "../noita_api_macro"}

View file

@ -0,0 +1,68 @@
pub mod lua;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EntityID(pub isize);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ComponentID(pub isize);
pub struct Obj(pub usize);
pub struct Color(pub u32);
noita_api_macro::generate_components!();
pub mod raw {
use super::{Color, ComponentID, EntityID, Obj};
use std::borrow::Cow;
use crate::lua::LuaState;
noita_api_macro::generate_api!();
fn component_get_value_base(
component: ComponentID,
field: &str,
expected_results: i32,
) -> eyre::Result<()> {
let lua = LuaState::current()?;
lua.get_global(c"ComponentGetValue2");
lua.push_integer(component.0);
lua.push_string(field);
lua.call(2, expected_results);
Ok(())
}
pub(crate) fn component_get_value_number(
component: ComponentID,
field: &str,
) -> eyre::Result<f64> {
component_get_value_base(component, field, 1)?;
let lua = LuaState::current()?;
let ret = lua.to_number(1);
lua.pop_last();
Ok(ret)
}
pub(crate) fn component_get_value_integer(
component: ComponentID,
field: &str,
) -> eyre::Result<i32> {
component_get_value_base(component, field, 1)?;
let lua = LuaState::current()?;
let ret = lua.to_integer(1);
lua.pop_last();
Ok(ret as i32)
}
pub(crate) fn component_get_value_bool(
component: ComponentID,
field: &str,
) -> eyre::Result<bool> {
component_get_value_base(component, field, 1)?;
let lua = LuaState::current()?;
let ret = lua.to_bool(1);
lua.pop_last();
Ok(ret)
}
}

View file

@ -1,20 +1,24 @@
pub mod lua_bindings;
use std::{ use std::{
cell::Cell, cell::Cell,
ffi::{c_char, c_int, CStr}, ffi::{c_char, c_int, CStr},
mem, slice, mem, slice,
sync::LazyLock,
}; };
use eyre::{bail, Context, OptionExt}; use eyre::{bail, Context, OptionExt};
use lua_bindings::{lua_CFunction, lua_State, Lua51, LUA_GLOBALSINDEX};
use crate::{
lua_bindings::{lua_CFunction, lua_State, LUA_GLOBALSINDEX},
LUA,
};
thread_local! { thread_local! {
static CURRENT_LUA_STATE: Cell<Option<LuaState>> = Cell::default(); static CURRENT_LUA_STATE: Cell<Option<LuaState>> = Cell::default();
} }
pub static LUA: LazyLock<Lua51> = LazyLock::new(|| unsafe {
let lib = libloading::Library::new("./lua51.dll").expect("library to exist");
Lua51::from_library(lib).expect("library to be lua")
});
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct LuaState { pub struct LuaState {
lua: *mut lua_State, lua: *mut lua_State,
@ -36,7 +40,7 @@ impl LuaState {
CURRENT_LUA_STATE.set(Some(self)); CURRENT_LUA_STATE.set(Some(self));
} }
pub(crate) fn raw(&self) -> *mut lua_State { pub fn raw(&self) -> *mut lua_State {
self.lua self.lua
} }
@ -117,12 +121,12 @@ impl LuaState {
} }
} }
pub(crate) trait LuaFnRet { pub trait LuaFnRet {
fn do_return(self, lua: LuaState) -> c_int; fn do_return(self, lua: LuaState) -> c_int;
} }
/// Function intends to return several values that it has on stack. /// Function intends to return several values that it has on stack.
pub(crate) struct ValuesOnStack(pub(crate) c_int); pub struct ValuesOnStack(pub c_int);
impl LuaFnRet for ValuesOnStack { impl LuaFnRet for ValuesOnStack {
fn do_return(self, _lua: LuaState) -> c_int { fn do_return(self, _lua: LuaState) -> c_int {
@ -141,7 +145,7 @@ impl<R: LuaFnRet> LuaFnRet for eyre::Result<R> {
match self { match self {
Ok(ok) => ok.do_return(lua), Ok(ok) => ok.do_return(lua),
Err(err) => unsafe { Err(err) => unsafe {
lua.raise_error(format!("Error in ewext call: {:?}", err)); lua.raise_error(format!("Error in rust call: {:?}", err));
}, },
} }
} }

View file

@ -1,3 +1,7 @@
[workspace]
resolver = "2"
members = ["noita_api", "noita_api_macro"]
[package] [package]
name = "noita_api_macro" name = "noita_api_macro"
version = "0.1.0" version = "0.1.0"

View file

@ -201,7 +201,7 @@ fn generate_code_for_component(com: Component) -> proc_macro2::TokenStream {
quote! { quote! {
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
pub struct #component_name(pub(crate) ComponentID); pub struct #component_name(pub ComponentID);
impl #component_name { impl #component_name {
#(#impls)* #(#impls)*
@ -271,7 +271,7 @@ fn generate_code_for_api_fn(api_fn: ApiFn) -> proc_macro2::TokenStream {
quote! { quote! {
#[doc = #fn_doc] #[doc = #fn_doc]
pub(crate) fn #fn_name(#(#args,)*) -> eyre::Result<#ret_type> { pub fn #fn_name(#(#args,)*) -> eyre::Result<#ret_type> {
let lua = LuaState::current()?; let lua = LuaState::current()?;
lua.get_global(#fn_name_c); lua.get_global(#fn_name_c);
@ -304,9 +304,9 @@ pub fn add_lua_fn(item: TokenStream) -> TokenStream {
let fn_name_c = name_to_c_literal(fn_name); let fn_name_c = name_to_c_literal(fn_name);
quote! { quote! {
unsafe extern "C" fn #bridge_fn_name(lua: *mut lua_State) -> c_int { unsafe extern "C" fn #bridge_fn_name(lua: *mut lua_State) -> c_int {
let lua_state = LuaState::new(lua); let lua_state = noita_api::lua::LuaState::new(lua);
lua_state.make_current(); lua_state.make_current();
crate::lua_state::LuaFnRet::do_return(#fn_name_ident(lua_state), lua_state) noita_api::lua::LuaFnRet::do_return(#fn_name_ident(lua_state), lua_state)
} }
LUA.lua_pushcclosure(lua, Some(#bridge_fn_name), 0); LUA.lua_pushcclosure(lua, Some(#bridge_fn_name), 0);

View file

@ -1,11 +1,9 @@
use std::{mem, os::raw::c_void, ptr, sync::OnceLock}; use std::{mem, os::raw::c_void, ptr, sync::OnceLock};
use iced_x86::{Decoder, DecoderOptions, Mnemonic}; use iced_x86::{Decoder, DecoderOptions, Mnemonic};
use noita_api::lua::LuaState;
use crate::{ use crate::noita::ntypes::{EntityManager, ThiscallFn};
lua_state::LuaState,
noita::ntypes::{EntityManager, ThiscallFn},
};
static GRABBED: OnceLock<Grabbed> = OnceLock::new(); static GRABBED: OnceLock<Grabbed> = OnceLock::new();

View file

@ -1,31 +1,21 @@
use crate::noita::api::DamageModelComponent;
use std::{ use std::{
arch::asm, arch::asm,
cell::{LazyCell, RefCell}, cell::{LazyCell, RefCell},
ffi::{c_int, c_void}, ffi::{c_int, c_void},
sync::LazyLock,
time::Instant, time::Instant,
}; };
use addr_grabber::{grab_addrs, grabbed_fns, grabbed_globals}; use addr_grabber::{grab_addrs, grabbed_fns, grabbed_globals};
use eyre::bail; use eyre::bail;
use lua_bindings::{lua_State, Lua51};
use lua_state::{LuaState, ValuesOnStack};
use noita::{ntypes::Entity, pixel::NoitaPixelRun, ParticleWorldState};
use noita_api_macro::add_lua_fn;
mod lua_bindings; use noita::{ntypes::Entity, pixel::NoitaPixelRun, ParticleWorldState};
pub mod lua_state; use noita_api::lua::{lua_bindings::lua_State, LuaState, ValuesOnStack, LUA};
use noita_api_macro::add_lua_fn;
pub mod noita; pub mod noita;
mod addr_grabber; mod addr_grabber;
static LUA: LazyLock<Lua51> = LazyLock::new(|| unsafe {
let lib = libloading::Library::new("./lua51.dll").expect("library to exist");
Lua51::from_library(lib).expect("library to be lua")
});
thread_local! { thread_local! {
static STATE: LazyCell<RefCell<ExtState>> = LazyCell::new(|| { static STATE: LazyCell<RefCell<ExtState>> = LazyCell::new(|| {
println!("Initializing ExtState"); println!("Initializing ExtState");
@ -69,7 +59,7 @@ fn encode_area(lua: LuaState) -> ValuesOnStack {
let runs = unsafe { pws.encode_area(start_x, start_y, end_x, end_y, encoded_buffer) }; let runs = unsafe { pws.encode_area(start_x, start_y, end_x, end_y, encoded_buffer) };
unsafe { LUA.lua_pushinteger(lua, runs as isize) }; unsafe { LUA.lua_pushinteger(lua, runs as isize) };
}); });
lua_state::ValuesOnStack(1) ValuesOnStack(1)
} }
fn make_ephemerial(lua: LuaState) -> eyre::Result<()> { fn make_ephemerial(lua: LuaState) -> eyre::Result<()> {
@ -105,12 +95,12 @@ fn bench_fn(_lua: LuaState) -> eyre::Result<()> {
let start = Instant::now(); let start = Instant::now();
let iters = 10000; let iters = 10000;
for _ in 0..iters { for _ in 0..iters {
let player = noita::api::raw::entity_get_closest_with_tag(0.0, 0.0, "player_unit".into())?; let player = noita_api::raw::entity_get_closest_with_tag(0.0, 0.0, "player_unit".into())?;
noita::api::raw::entity_set_transform(player, 0.0, Some(0.0), None, None, None)?; noita_api::raw::entity_set_transform(player, 0.0, Some(0.0), None, None, None)?;
} }
let elapsed = start.elapsed(); let elapsed = start.elapsed();
noita::api::raw::game_print( noita_api::raw::game_print(
format!( format!(
"Took {}us to test, {}ns per call", "Took {}us to test, {}ns per call",
elapsed.as_micros(), elapsed.as_micros(),
@ -123,15 +113,15 @@ fn bench_fn(_lua: LuaState) -> eyre::Result<()> {
} }
fn test_fn(_lua: LuaState) -> eyre::Result<()> { fn test_fn(_lua: LuaState) -> eyre::Result<()> {
let player = noita::api::raw::entity_get_closest_with_tag(0.0, 0.0, "player_unit".into())?; let player = noita_api::raw::entity_get_closest_with_tag(0.0, 0.0, "player_unit".into())?;
let damage_model = DamageModelComponent(noita::api::raw::entity_get_first_component( let damage_model = noita_api::DamageModelComponent(noita_api::raw::entity_get_first_component(
player, player,
"DamageModelComponent".into(), "DamageModelComponent".into(),
None, None,
)?); )?);
let hp = damage_model.hp()?; let hp = damage_model.hp()?;
noita::api::raw::game_print( noita_api::raw::game_print(
format!("Component: {:?}, Hp: {}", damage_model.0, hp * 25.0).into(), format!("Component: {:?}, Hp: {}", damage_model.0, hp * 25.0).into(),
)?; )?;

View file

@ -3,75 +3,6 @@ use std::{ffi::c_void, mem};
pub(crate) mod ntypes; pub(crate) mod ntypes;
pub(crate) mod pixel; pub(crate) mod pixel;
pub mod api {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EntityID(isize);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ComponentID(isize);
pub struct Obj(usize);
pub struct Color(u32);
noita_api_macro::generate_components!();
pub mod raw {
use super::{Color, ComponentID, EntityID, Obj};
use std::borrow::Cow;
use crate::LuaState;
noita_api_macro::generate_api!();
fn component_get_value_base(
component: ComponentID,
field: &str,
expected_results: i32,
) -> eyre::Result<()> {
let lua = LuaState::current()?;
lua.get_global(c"ComponentGetValue2");
lua.push_integer(component.0);
lua.push_string(field);
lua.call(2, expected_results);
Ok(())
}
pub(crate) fn component_get_value_number(
component: ComponentID,
field: &str,
) -> eyre::Result<f64> {
component_get_value_base(component, field, 1)?;
let lua = LuaState::current()?;
let ret = lua.to_number(1);
lua.pop_last();
Ok(ret)
}
pub(crate) fn component_get_value_integer(
component: ComponentID,
field: &str,
) -> eyre::Result<i32> {
component_get_value_base(component, field, 1)?;
let lua = LuaState::current()?;
let ret = lua.to_integer(1);
lua.pop_last();
Ok(ret as i32)
}
pub(crate) fn component_get_value_bool(
component: ComponentID,
field: &str,
) -> eyre::Result<bool> {
component_get_value_base(component, field, 1)?;
let lua = LuaState::current()?;
let ret = lua.to_bool(1);
lua.pop_last();
Ok(ret)
}
}
}
pub(crate) struct ParticleWorldState { pub(crate) struct ParticleWorldState {
pub(crate) _world_ptr: *mut c_void, pub(crate) _world_ptr: *mut c_void,
pub(crate) chunk_map_ptr: *mut c_void, pub(crate) chunk_map_ptr: *mut c_void,