Open ConnorBP opened 8 months ago
The console integration examples print command still fails to get LuaWorld from "world" on script load for some reason here. Not quite sure why....
I'm gonna come back to it with fresh eyes and maybe realize that I forgot to call a function somewhere, but please do let me know if you spot it.
I should mention, one thing the changes so far have made possible which was not possible previously is this use case:
#[derive(Default)]
struct Export;
impl tealr::mlu::ExportInstances for Export {
fn add_instances<'lua, T: tealr::mlu::InstanceCollector<'lua>>(
self,
instance_collector: &mut T,
) -> mlua::Result<()> {
instance_collector
// .document_instance("The root collection of API modules making up the Lychee API")
// .add_instance("lychee", |ctx| {
// Ok(ctx.create_table_from(vec![("test", LycheeAPIModule)])?)
// })?
.document_instance("Utility functions for interacting with the game memory directly.")
.add_instance("memory", |ctx| {
if let Some(processr) = ctx
.get_world()
.map_err(|e| {
mlua::Error::RuntimeError(format!(
"Failed getting world in tealr lua api init: {e}"
))
})?
.read()
.get_resource::<ProcessR<IntoProcessInstance<CBox<c_void>, CArc<c_void>>>>()
{
Ok(MemoryAPIModule {
process: processr.0.clone(),
})
} else {
return Err(mlua::Error::RuntimeError(
"failed to get memflow process resource".to_string(),
));
}
})
.map_err(|e| mlua::Error::RuntimeError(format!("{e}")))?;
Ok(())
}
}
Before the changes in this PR the globals variable was not set so it was not possible to initialize modules content in the instance collector with any meaningful data.
The fact that this is working now means that the globals are in-fact set, so I am not quite sure why they are still inaccessible during script load execution. Something weird with the stack is going on I think?
Found the problem I believe. Its a cyclic dependency. The world cannot be injected the first time and fails because its type has no yet been defined by tealr in the add_instances. But if you call attach api first then the world passed to it is not yet set.
set("world", crate::lua::bevy::LuaWorld::new(world_ptr))
fails if
instances.add_instance(
"world",
crate::lua::util::DummyTypeName::<crate::lua::bevy::LuaWorld>::new,
)?;
was not called first.
Not sure what the best solution is. The quickest fix would be to call the initialization twice, but some way of splitting off the dependent sections into a third seperate stage would be ideal I think.
Found the problem I believe. Its a cyclic dependency. The world cannot be injected the first time and fails because its type has no yet been defined by tealr in the add_instances. But if you call attach api first then the world passed to it is not yet set.
set("world", crate::lua::bevy::LuaWorld::new(world_ptr))
fails if
instances.add_instance( "world", crate::lua::util::DummyTypeName::<crate::lua::bevy::LuaWorld>::new, )?;
was not called first.
Not sure what the best solution is. The quickest fix would be to call the initialization twice, but some way of splitting off the dependent sections into a third seperate stage would be ideal I think.
- Register Types by attaching bevy_api
- then setup runtime which causes world to be set
- then attach any apis dependent on world access
I was wrong. I don't think this was relevant at all. I now suspect it is because contexts.insert_context(script_data.to_owned(), Some(lua));
is called after the load script function.
edit: kill me please, I have no idea what is wrong with it.
I have been debugging this for days. I am completely at a loss as to why this function fails when called in a rust callback function that is bound to lua:
impl GetWorld for Lua {
type Error = mlua::Error;
fn get_world(&self) -> Result<WorldPointer, Self::Error> {
self.globals().get::<_, LuaWorld>("world").map(Into::into)
}
}
.get::<_, LuaWorld>("world")
here returns a nil. The craziest thing is that the world global is accessible just fine from the tealr add_instances()
function which is called shortly before this one. Either something is funky with the way the lua callbacks are being created, or world is being popped without being put back. I am very close to giving up but I might be close........ I have been close for days. :'(
Hi @ConnorBP apologies I haven't had much time for this project recently, I'll try have a look and help ASAP! This is all great work and I really appreciate it!
So i've had a quick look, Looks like the issues begin with this code:
// {
// providers.attach_all(&mut lua)?;
// }
commenting this out and modifying the console example script to:
Gives me this output:
so somehow the API attachment step resets the globals maybe?
Ahh, I believe the BevyAPIProvider uses this:
instances.add_instance(
"world",
crate::lua::util::DummyTypeName::<crate::lua::bevy::LuaWorld>::new,
)?;
To expose world in the docs, but this might be overwriting the world global in this case
Okay, here is the easy solution then, setting up the script runtime is very light, it's just setting up a world pointer, let's do it twice, once before attaching hte API so it's available there, then afterwards so it's available when the script loads, this shouldn't mess with docs generation and won't drag performance too much (plus only once per script). Otherwise we'd have to figure out another way of documenting these things but the tealr part of the system needs an overhaul later anyway so that can be addressed at the same time.
EDIT: Yes doing this fixed the problem
Okay, here is the easy solution then, setting up the script runtime is very light, it's just setting up a world pointer, let's do it twice, once before attaching hte API so it's available there, then afterwards so it's available when the script loads, this shouldn't mess with docs generation and won't drag performance too much (plus only once per script). Otherwise we'd have to figure out another way of documenting these things but the tealr part of the system needs an overhaul later anyway so that can be addressed at the same time.
EDIT: Yes doing this fixed the problem
Oh amazing! Nice work, thanks for the assist!
Hey @ConnorBP sorry for not reviewing in a while, I am doing some serious re-factoring and I have this issue in mind. I think soon this use case will be supported through a much more modular structure!
Hey @ConnorBP sorry for not reviewing in a while, I am doing some serious re-factoring and I have this issue in mind. I think soon this use case will be supported through a much more modular structure!
Excellent! :) should be much easier on the latest bevy as well. The branch for this PR works pretty well if you wanna try it out
If this PR makes world
available at script load time, I'm all about that! Any chance it could be resurrected? I see it's a little dated now. If it was rebased and working with main, would it be likely to be merged?
Hi @shanecelis, if I remember correctly the PR needed some more work before merging (testing, and I think porting this to the other scripting langs), if the demand is high I don't mind merging this work assuming somebody else does this work. However worth keeping in mind is these features will be supported in the big upcoming refactor over at: https://github.com/makspll/bevy_mod_scripting/pull/112 (but I cannot tell you when that will be ready)
Tentative initial work for exclusive system refactor. Still in todo:
example of what is trying to be fixed
List of changes to api from this PR:
event_writer: &mut EventWriter<ScriptLoaded>,
argument to reload and insert new functions with a resource_scope on the world pointer.