diff --git a/crates/bevy_mod_scripting_core/src/bindings/function/from_ref.rs b/crates/bevy_mod_scripting_core/src/bindings/function/from_ref.rs index 61c7130fd0..1a26658943 100644 --- a/crates/bevy_mod_scripting_core/src/bindings/function/from_ref.rs +++ b/crates/bevy_mod_scripting_core/src/bindings/function/from_ref.rs @@ -2,7 +2,9 @@ use std::{any::TypeId, ffi::OsString, path::PathBuf}; -use bevy::reflect::{DynamicEnum, DynamicList, DynamicTuple, DynamicVariant, PartialReflect}; +use bevy::reflect::{ + DynamicEnum, DynamicList, DynamicMap, DynamicTuple, DynamicVariant, Map, PartialReflect, +}; use crate::{ bindings::{function::from::FromScript, WorldGuard}, @@ -100,6 +102,23 @@ impl FromScriptRef for Box { } } + if let Some((key_type, val_type)) = type_info.map_inner_types() { + if let ScriptValue::Map(map) = value { + let mut dynamic_map = DynamicMap::default(); + for (key, val) in map { + let key = Self::from_script_ref( + key_type, + ScriptValue::String(key.into()), + world.clone(), + )?; + let val = Self::from_script_ref(val_type, val, world.clone())?; + dynamic_map.insert_boxed(key, val); + } + dynamic_map.set_represented_type(Some(type_info)); + return Ok(Box::new(dynamic_map)); + } + } + match value { ScriptValue::Reference(reflect_reference) => reflect_reference.to_owned_value(world), value => Err(InteropError::value_mismatch(target, value)), diff --git a/crates/bevy_mod_scripting_core/src/reflection_extensions.rs b/crates/bevy_mod_scripting_core/src/reflection_extensions.rs index a18d0ea051..9e7f5e57b6 100644 --- a/crates/bevy_mod_scripting_core/src/reflection_extensions.rs +++ b/crates/bevy_mod_scripting_core/src/reflection_extensions.rs @@ -419,6 +419,8 @@ impl PartialReflectExt for T { /// Extension trait for TypeInfos providing additional functionality for working with type information. pub trait TypeInfoExtensions { + /// Returns the inner type of the map if the type is a map, otherwise + fn map_inner_types(&self) -> Option<(TypeId, TypeId)>; /// Returns the inner type of the list if the type is a list, otherwise None. fn list_inner_type(&self) -> Option; /// Returns true if the type is a list. @@ -452,6 +454,11 @@ impl TypeInfoExtensions for TypeInfo { Some(self.as_list().ok()?.item_ty().id()) } + fn map_inner_types(&self) -> Option<(TypeId, TypeId)> { + let map = self.as_map().ok()?; + Some((map.key_ty().id(), map.value_ty().id())) + } + fn is_type(&self, crate_name: Option<&str>, type_ident: &str) -> bool { self.type_path_table().ident() == Some(type_ident) && self.type_path_table().crate_name() == crate_name diff --git a/crates/languages/bevy_mod_scripting_lua/tests/data/set/set_primitives_works.lua b/crates/languages/bevy_mod_scripting_lua/tests/data/set/set_primitives_works.lua index a01e3a4599..cc35c7764e 100644 --- a/crates/languages/bevy_mod_scripting_lua/tests/data/set/set_primitives_works.lua +++ b/crates/languages/bevy_mod_scripting_lua/tests/data/set/set_primitives_works.lua @@ -6,23 +6,29 @@ resource.bool = true resource.int = 42 resource.float = 3.0 resource.vec_usize = { 1, 2 } +resource.string_map = { foo = "hello", zoo = "world" } assert(resource.string == "Hello, World!", "Expected 'Hello, World!', got " .. resource.string) assert(resource.bool == true, "Expected true, got " .. tostring(resource.bool)) assert(resource.int == 42, "Expected 42, got " .. resource.int) assert(resource.float == 3.0, "Expected 3.14, got " .. resource.float) assert(resource.vec_usize[1] == 1, "Expected 1, got " .. resource.vec_usize[1]) +assert(resource.string_map:len() == 2, "Expected 2, got " .. resource.string_map:len()) +-- assert(resource.string_map["foo"] == "hello", "Expected 'hello', got " .. resource.string_map["foo"]) +-- assert(resource.string_map["zoo"] == "world", "Expected 'world', got " .. resource.string_map["zoo"]) resource.string = "Goodbye, World!" resource.bool = false resource.int = 24 resource.float = 1.0 resource.vec_usize = { 3, 4 } +resource.string_map = { foo = "goodbye", zoo = "world" } assert(resource.string == "Goodbye, World!", "Expected 'Goodbye, World!', got " .. resource.string) assert(resource.bool == false, "Expected false, got " .. tostring(resource.bool)) assert(resource.int == 24, "Expected 24, got " .. resource.int) assert(resource.float == 1.0, "Expected 1.41, got " .. resource.float) -assert(resource.vec_usize[1] == 3, "Expected 3, got " .. resource.vec_usize[1]) - +assert(resource.string_map:len() == 2, "Expected 2, got " .. resource.string_map:len()) +-- assert(resource.string_map["foo"] == "goodbye", "Expected 'goodbye', got " .. resource.string_map["foo"]) +-- assert(resource.string_map["zoo"] == "world", "Expected 'world', got " .. resource.string_map["zoo"]) diff --git a/crates/languages/bevy_mod_scripting_rhai/tests/data/set/set_primitives_works.rhai b/crates/languages/bevy_mod_scripting_rhai/tests/data/set/set_primitives_works.rhai index 8ae0d6d4e8..820b094b60 100644 --- a/crates/languages/bevy_mod_scripting_rhai/tests/data/set/set_primitives_works.rhai +++ b/crates/languages/bevy_mod_scripting_rhai/tests/data/set/set_primitives_works.rhai @@ -6,23 +6,36 @@ resource.bool = true; resource.int = 42; resource.float = 3.0; resource.vec_usize = [ 1, 2 ]; +resource.string_map = #{ + foo: "string1", + zoo: "string2" +}; assert(resource.string == "Hello, World!", "Expected 'Hello, World!', got " + resource.string); assert(resource.bool == true, "Expected true, got " + resource.bool); assert(resource.int == 42, "Expected 42, got " + resource.int); assert(resource.float == 3.0, "Expected 3.14, got " + resource.float); assert(resource.vec_usize[0] == 1, "Expected 1, got " + resource.vec_usize[1]); +assert(resource.string_map.len.call() == 2, "Expected 2, got " + resource.string_map.len.call()); +// assert(resource.string_map.foo == "string1", "Expected 'string1', got " + resource.string_map.foo); +// assert(resource.string_map.zoo == "string2", "Expected 'string2', got " + resource.string_map.zoo); resource.string = "Goodbye, World!"; resource.bool = false; resource.int = 24; resource.float = 1.0; resource.vec_usize = [ 3, 4 ]; +resource.string_map = #{ + foo: "goodbye", + zoo: "world" +}; assert(resource.string == "Goodbye, World!", "Expected 'Goodbye, World!', got " + resource.string); assert(resource.bool == false, "Expected false, got " + resource.bool); assert(resource.int == 24, "Expected 24, got " + resource.int); assert(resource.float == 1.0, "Expected 1.41, got " + resource.float); assert(resource.vec_usize[0] == 3, "Expected 3, got " + resource.vec_usize[1]); - +assert(resource.string_map.len.call() == 2, "Expected 2, got " + resource.string_map.len.call()); +// assert(resource.string_map.foo == "goodbye", "Expected 'goodbye', got " + resource.string_map.foo); +// assert(resource.string_map.zoo == "world", "Expected 'world', got " + resource.string_map.zoo); diff --git a/crates/testing_crates/test_utils/src/test_data.rs b/crates/testing_crates/test_utils/src/test_data.rs index b1bf0341e4..4f97c80a3b 100644 --- a/crates/testing_crates/test_utils/src/test_data.rs +++ b/crates/testing_crates/test_utils/src/test_data.rs @@ -1,4 +1,5 @@ use std::alloc::Layout; +use std::collections::HashMap; use bevy::asset::AssetPlugin; use bevy::ecs::{component::*, world::World}; @@ -124,6 +125,7 @@ pub struct TestResourceWithVariousFields { pub float: f32, pub bool: bool, pub vec_usize: Vec, + pub string_map: HashMap, } impl TestResourceWithVariousFields { @@ -135,6 +137,10 @@ impl TestResourceWithVariousFields { float: 69.0, bool: true, vec_usize: vec![1, 2, 3, 4, 5], + string_map: vec![("foo", "bar"), ("zoo", "zed")] + .into_iter() + .map(|(a, b)| (a.to_owned(), b.to_owned())) + .collect(), } } }