bevy_mod_scripting
bevy_mod_scripting copied to clipboard
Improved proxy generating macros
Current macros are very ugly, written before I had a full grasp of the capabilities of rust meta-programming,
I intend to make things like these possible:
#[derive(ScriptProxy, Reflect)]
#[proxy(languages("on_feature(lua)"))]
#[functions[
#[lua(MutatingMetaMethod)]
fn basd(mut self) {
}
#[lua(MetaMethod)]
fn asd(self);
#[lua(Function)]
fn basda(self);
]]
pub struct Lol {}
I can take a peek at this in a few days!
Sure thing!
I've been working on the Lua version of this over at this branch: https://github.com/makspll/bevy_mod_scripting/tree/feature/derive_macros
I've got a basic macro going there. Similar work needs to be done for Rhai and can this easily be done in parallel if you're interested! Rhai however does not yet have existing proxy macros, but the crate itself has a lot of cool features which would make it interact nicely with a macro structure like the one above (and you'd probably want to bump its version).
Generally the vague steps would be:
- [ ] Set up macro structure akin to how it's done on the branch above (the main crate uses a derive macro which then calls a proc macro for each language crate (since proc macros are more flexible)), output no code.
- [ ] Let the macro generate the proxy definition (this is done via a helper macro
bevy_script_api::make_script_wrapper!), think of these as a container on the script side which can either be a reference to a bevy thing (via their reflection mechanism) or an actual value of the type stored "script-side". - [ ] Once the macro generates a proxy now it needs to implement some traits on the PROXIED TYPE, the core one is
RhaiProxyable, have a look atbevy_script_api/src/rhai/mod.rswhere important traits are defined. The most important mechanism you need to be aware of is how our type gets resolved to its proxy on the script side, and this happens here:
impl ToDynamic for ScriptRef {
fn to_dynamic(self) -> Result<Dynamic, Box<EvalAltResult>> {
// clone since it's cheap and we don't want to clone self later
let world = self.world_ptr.clone();
let world = world.read();
let type_data = world.resource::<AppTypeRegistry>();
let g = type_data.read();
let type_id = self.get(|s| s.type_id())?;
if let Some(v) = g.get_type_data::<ReflectRhaiProxyable>(type_id) { // if it implements ReflectRhaiProxyable, then the trait is used to generate a proxy and this gets used on the script side when interacting with the world
v.ref_to_rhai(self)
} else {
// otherwise we just use a generic type which handles very simple operations but nothing more
ReflectedValue { ref_: self }.to_dynamic()
}
}
}
- [ ] if you register this type with the app using
bevy_script_api::register_foreign_rhai_type, you will now be able to useScriptWorldin a rhai script to retrieve your proxy in a script via (have a look at thebevy_api_rhai.rsexample for how to setup a world to test this) :
let my_component_type = world.get_type_by_name("MyComponent");
let my_component = world.get_component(entity,my_component_type);
- [ ] now what's left is actually automatically
proxyingfunctions ,fields etc, this is the hard bit. Like with the Lua macros, for this you'd look at the types inbevy_script_api/src/rhai/bevy/mod.rswhich defines some script-side api types and for each function, field, operator etc, you'd want to use the proxy functions available to you to convert invocations of these functions on the script side, so that the arguments which correspond to other proxies generated with the same macro, are resolved to their "proxied" types, the operation is then performed over these "inner" types, and the result is converted to its proxy via the traits you implemented earlier and returned.
Doing any of the above would be helpful!
Alright, will be starting to look at this tomorrow!
Hey there - I'm finally getting around to this, and I'm currently spending my time trying to better understand the structure of the Lua interops so I can port most of them to Rhai, but progress has been started and will be built upon. It may take me a bit, as I've been laid off as of a few days ago and need to devote my time to finding a way to pay rent, but my down time will be tackling this issue. Just wanted to communicate that!
Hey man, no worries. That's very rough and I hope you find a new job soon! Any help is much appreciated, but of course there is no rush!
@makspll I've opened a draft PR which is very much a work in progress, but I wanted to open it so you could see the work that was being done as my understanding/knowledge on the project progresses and make any suggestions/comments as you see fit.
@thedanvail of course I will have a look now and keep a regular watch in parallel to developing the Lua branch.