Closed zwazel closed 10 months ago
TL;DR: in your api provider attach_api add:
api.register_vec_functions::<u64>();
then you should be able to simply:
for lobby in lobby_list.0 {
print(`elem: ${e}`);
}
Hey, you're missing a link between the reflection system and your custom 'proxy'
So the way ReflectedValue works is it looks for registrations of RhaiProxyable
traits on the types you're accessing when traversing your type via field accessors, Vec<T>
actually already has a custom type implemented for it hooked into via:
impl<T: RhaiVecElem> RhaiProxyable for Vec<T> {
fn ref_to_rhai(self_: crate::ScriptRef) -> Result<Dynamic, Box<EvalAltResult>> {
Ok(Dynamic::from(RhaiVec::<T>::new_ref(self_)))
}
// ...
}
The logical path from get_resource
is as follows (with error paths and other things simplified away for brevity):
CustomType
for the ScriptWorld
let resource : Option<ScriptRef> = self_.get_resource(res_type)?;
if let Some(c) = resource {
c.to_dynamic()
} else {
Ok(Default::default())
}
The common ScriptWorld::get_resource
method shared by all languages
pub fn get_resource(
&self,
res_type: ScriptTypeRegistration,
) -> Result<Option<ScriptRef>, ScriptError> {
let w = self.read();
let resource_data = res_type.data::<ReflectResource>()?;
Ok(resource_data
.reflect(&w)
.map(|_res| ScriptRef::new_resource_ref(resource_data.clone(), self.clone().into())))
}
The ScriptRef::to_dynamic
implementation
impl ToDynamic for ScriptRef {
fn to_dynamic(self) -> Result<Dynamic, Box<EvalAltResult>> {
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())?;
// IMPORTANT
if let Some(v) = g.get_type_data::<ReflectRhaiProxyable>(type_id) {
v.ref_to_rhai(self)
} else {
ReflectedValue { ref_: self }.to_dynamic()
}
}
}
.with_indexer_get_result(|obj: &mut ReflectedValue, index: Dynamic| {
obj.ref_.index(index)?.to_dynamic()
})
So basically the type data corresponding to ReflectRhaiProxyable decides how the value is converted into a Rhai value, if it doesn't exist you get a ReflectedValue
type which is the most generic reflection primitive. I believe you're missing the hooks which register the RhaiProxyable
traits against your particular types like in the rhai/bevy_api.rs
example:
fn attach_api(&mut self, api: &mut Self::APITarget) -> Result<(), ScriptError> {
api.set_max_expr_depths(999, 999);
// one for each type corresponding to T in your Vec<T>
api.register_vec_functions::<Option<bool>>();
api.register_vec_functions::<bool>();
Ok(())
}
try adding those and see if your value converts to a RhaiVec
then you should be able to simply:
for lobby in lobby_list.0 { print(`elem: ${e}`); }
I get a Syntax error: Error in loading script lobby_list_container.rhai: Syntax error for script "script_name" Expecting name of a property
.
So using .0 does not work, it seems. I changed the resource from a tuple to a struct.
And that works.
But surprisingly, trying to loop through the empty array causes a crash.
if world.has_resource(lobby_list_type) {
let lobbies = world.get_resource(lobby_list_type).lobbies;
for lobby in lobbies {
print(`lobby: ${lobby}`);
}
}
The Crash error:
thread 'Compute Task Pool (0)' panicked at 'called `Option::unwrap()` on a `None` value', C:\...\.cargo\git\checkouts\bevy_mod_scripting-ff78cea4271e6409\6bafad2\bevy_mod_scripting_core\src\hosts.rs:364:57
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_mod_scripting_core::systems::script_hot_reload_handler<bevy_mod_scripting_rhai::RhaiScriptHost<pgc::modding::ModdedScriptRuntimeArguments>>`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
Which surprised me, i expected it to just act like a normal for loop and skip it when it's empty. For now I can workaround by just checking if its empty first:
if world.has_resource(lobby_list_type) {
let lobbies = world.get_resource(lobby_list_type).lobbies;
if !lobbies.is_empty() {
for lobby in lobbies {
print(`lobby: ${lobby}`);
}
}
}
Is this a confirmed bug or intended behaviour? I can open another issue if you want for this.
I've created a new branch on my local version and will look into it, i already found a place to add on #68. Will create a Pull Request later
Hey, indeed looks like a bug, please open another issue for the bug so it's easier to find for others :) thanks a lot!
As for accessing the tuple struct, it might be we need slightly different syntax try with '[0]' or '._0' I'll need to check back what this was for rhai
I think I need to get around to building a test tool for all off the common usage patterns of the script APIs
I've opened issue #86 and will close this one.
Following scenario, i get a resource
This resource looks like this:
Quite simple. I now want to access the different lobbies from the vec, I figured out that I can just access them by indexing.
this works. But I'd like to loop through them:
Which gives me following error:
Runtime error in script "script_name.rhai" For loop expects iterable type
. So I looked into Rhai and how you've implemented some things. For example, I can use theapi.build_type
in theattach_api
of an APIProvider, and register some functions as well as it being iterable:But that doesn't solve my problem, because the script only gets a ReflectedValue. So i'm wondering if there is a way for me to turn a ReflectedValue into a specific Type?