Allow Vec<T> in returns

This commit is contained in:
IQuant 2024-11-25 22:42:26 +03:00
parent 0f26126ad9
commit 2c065fc4f7
6 changed files with 968 additions and 274 deletions

View file

@ -26,7 +26,7 @@ impl EntityID {
tag: Option<Cow<'_, str>>,
) -> eyre::Result<Option<C>> {
raw::entity_get_first_component(self, C::NAME_STR.into(), tag)
.map(|x| x.map(Into::into))
.map(|x| x.flatten().map(Into::into))
.wrap_err_with(|| eyre!("Failed to get first component {} for {self:?}", C::NAME_STR))
}
pub fn get_first_component<C: Component>(self, tag: Option<Cow<'_, str>>) -> eyre::Result<C> {

View file

@ -105,6 +105,19 @@ impl LuaState {
unsafe { LUA.lua_getfield(self.lua, LUA_GLOBALSINDEX, name.as_ptr()) };
}
pub fn objlen(&self, index: i32) -> usize {
unsafe { LUA.lua_objlen(self.lua, index) }
}
pub fn index_table(&self, table_index: i32, index_in_table: usize) {
self.push_integer(index_in_table as isize);
if table_index < 0 {
unsafe { LUA.lua_gettable(self.lua, table_index - 1) };
} else {
unsafe { LUA.lua_gettable(self.lua, table_index) };
}
}
pub fn pop_last(&self) {
unsafe { LUA.lua_settop(self.lua, -2) };
}
@ -122,6 +135,10 @@ impl LuaState {
// lua_error does not return.
unreachable!()
}
fn is_nil_or_none(&self, index: i32) -> bool {
(unsafe { LUA.lua_type(self.lua, index) }) <= 0
}
}
/// Used for types that can be returned from functions that were defined in rust to lua.
@ -346,6 +363,33 @@ impl LuaGetValue for Color {
}
}
impl<T: LuaGetValue> LuaGetValue for Option<T> {
fn get(lua: LuaState, index: i32) -> eyre::Result<Self> {
Ok(if lua.is_nil_or_none(index) {
None
} else {
Some(T::get(lua, index)?)
})
}
}
impl<T: LuaGetValue> LuaGetValue for Vec<T> {
fn get(lua: LuaState, index: i32) -> eyre::Result<Self> {
if T::size_on_stack() != 1 {
bail!("Encountered Vec<T> where T needs more than 1 slot on the stack. This isn't supported");
}
let len = lua.objlen(index);
let mut res = Vec::with_capacity(len);
for i in 1..=len {
lua.index_table(index, dbg!(i));
let get = T::get(lua, -1);
lua.pop_last();
res.push(get?);
}
Ok(res)
}
}
impl<T0: LuaGetValue, T1: LuaGetValue> LuaGetValue for (T0, T1) {
fn get(lua: LuaState, index: i32) -> eyre::Result<Self>
where

View file

@ -108,7 +108,24 @@ struct FnArg {
struct FnRet {
// name: String,
typ: Typ2,
// optional: bool,
optional: bool,
is_vec: bool,
}
impl FnRet {
fn as_rust_type_return(&self) -> proc_macro2::TokenStream {
let mut ret = self.typ.as_rust_type_return();
if self.is_vec {
ret = quote! {
Vec<#ret>
};
}
if self.optional {
ret = quote! {
Option<#ret>
};
}
ret
}
}
#[derive(Deserialize)]
@ -230,9 +247,9 @@ fn generate_code_for_api_fn(api_fn: ApiFn) -> proc_macro2::TokenStream {
} else {
if api_fn.rets.len() == 1 {
let ret = api_fn.rets.first().unwrap();
ret.typ.as_rust_type_return()
ret.as_rust_type_return()
} else {
let ret_types = api_fn.rets.iter().map(|ret| ret.typ.as_rust_type_return());
let ret_types = api_fn.rets.iter().map(|ret| ret.as_rust_type_return());
quote! { ( #(#ret_types),* ) }
}
};

File diff suppressed because it is too large Load diff

View file

@ -123,18 +123,15 @@ fn test_fn(_lua: LuaState) -> eyre::Result<()> {
let hp = damage_model.hp()?;
damage_model.set_hp(hp - 1.0)?;
let transform = noita_api::raw::entity_get_transform(player)?;
let (x, y, _, _, _) = noita_api::raw::entity_get_transform(player)?;
noita_api::raw::game_print(
format!(
"Component: {:?}, Hp: {}, tranform: {:?}",
damage_model.0,
hp * 25.0,
transform
)
.into(),
format!("Component: {:?}, Hp: {}", damage_model.0, hp * 25.0,).into(),
)?;
let entities = noita_api::raw::entity_get_in_radius_with_tag(x, y, 300.0, "enemy".into())?;
noita_api::raw::game_print(format!("{:?}", entities).into())?;
// noita::api::raw::entity_set_transform(player, 0.0, 0.0, 0.0, 1.0, 1.0)?;
Ok(())

View file

@ -27,6 +27,10 @@ def maybe_map_types(name, typ):
typ = "bool"
if typ == "boolean":
typ = "bool"
if typ == "item_entity_id":
typ = "entity_id"
if typ == "physics_body_id":
raise ValueError(f"{typ} not supported")
return typ
def parse_arg(arg_s):
@ -61,10 +65,15 @@ def parse_ret(ret_s):
if "|" in ret_s:
raise ValueError("multiple return types not supported")
if "{" in ret_s:
raise ValueError("tables in returns not supported")
if "multiple_types" in ret_s:
raise ValueError("no 'multiple_types' either")
returns_vec = False
if ret_s.startswith("{"):
ret_s = ret_s.removeprefix("{").removesuffix("}")
returns_vec = True
if "-" in ret_s:
raise ValueError("No support for key-value tables in returns")
typ = ret_s
name = None
@ -80,7 +89,8 @@ def parse_ret(ret_s):
return {
"name": name,
"typ": typ,
"optional": optional
"optional": optional,
"is_vec": returns_vec,
}