mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 12:43:34 +00:00
props: derive, get/set, example
This commit is contained in:
parent
9368242013
commit
da8daa051b
6 changed files with 325 additions and 66 deletions
|
@ -153,6 +153,10 @@ path = "examples/input/input_keyboard.rs"
|
||||||
name = "load_scene"
|
name = "load_scene"
|
||||||
path = "examples/scene/load_scene.rs"
|
path = "examples/scene/load_scene.rs"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "props"
|
||||||
|
path = "examples/scene/props.rs"
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "shader_custom_material"
|
name = "shader_custom_material"
|
||||||
path = "examples/shader/shader_custom_material.rs"
|
path = "examples/shader/shader_custom_material.rs"
|
||||||
|
|
|
@ -50,6 +50,85 @@ pub fn derive_resource(input: TokenStream) -> TokenStream {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(Properties, attributes(prop, module))]
|
||||||
|
pub fn derive_props(input: TokenStream) -> TokenStream {
|
||||||
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
|
let fields = match &ast.data {
|
||||||
|
Data::Struct(DataStruct {
|
||||||
|
fields: Fields::Named(fields),
|
||||||
|
..
|
||||||
|
}) => &fields.named,
|
||||||
|
_ => panic!("expected a struct with named fields"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let modules = get_modules(&ast);
|
||||||
|
let bevy_props_path = get_path(&modules.bevy_props);
|
||||||
|
|
||||||
|
let field_names = fields.iter().map(|field| field.ident
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.to_string()).collect::<Vec<String>>();
|
||||||
|
let field_idents = fields.iter().map(|field| field.ident.as_ref().unwrap()).collect::<Vec<_>>();
|
||||||
|
let field_count = fields.len();
|
||||||
|
let field_indices = (0..field_count).collect::<Vec<usize>>();
|
||||||
|
|
||||||
|
|
||||||
|
let generics = ast.generics;
|
||||||
|
let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
|
||||||
|
|
||||||
|
let struct_name = &ast.ident;
|
||||||
|
|
||||||
|
TokenStream::from(quote! {
|
||||||
|
impl #impl_generics #bevy_props_path::Props for #struct_name#ty_generics {
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
fn prop(&self, name: &str) -> Option<&dyn #bevy_props_path::Prop> {
|
||||||
|
match name {
|
||||||
|
#(#field_names => Some(&self.#field_idents),)*
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn #bevy_props_path::Prop> {
|
||||||
|
match name {
|
||||||
|
#(#field_names => Some(&mut self.#field_idents),)*
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prop_with_index(&self, index: usize) -> Option<&dyn #bevy_props_path::Prop> {
|
||||||
|
match index {
|
||||||
|
#(#field_indices => Some(&self.#field_idents),)*
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prop_with_index_mut(&mut self, index: usize) -> Option<&mut dyn #bevy_props_path::Prop> {
|
||||||
|
match index {
|
||||||
|
#(#field_indices => Some(&mut self.#field_idents),)*
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prop_name(&self, index: usize) -> Option<&str> {
|
||||||
|
match index {
|
||||||
|
#(#field_indices => Some(#field_names),)*
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prop_len(&self) -> usize {
|
||||||
|
#field_count
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter_props(&self) -> #bevy_props_path::PropIter {
|
||||||
|
#bevy_props_path::PropIter::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Uniform, attributes(uniform, module))]
|
#[proc_macro_derive(Uniform, attributes(uniform, module))]
|
||||||
pub fn derive_uniform(input: TokenStream) -> TokenStream {
|
pub fn derive_uniform(input: TokenStream) -> TokenStream {
|
||||||
let ast = parse_macro_input!(input as DeriveInput);
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
|
@ -11,6 +11,8 @@ pub struct ModuleAttributeArgs {
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
pub bevy_core: Option<String>,
|
pub bevy_core: Option<String>,
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
|
pub bevy_props: Option<String>,
|
||||||
|
#[darling(default)]
|
||||||
pub bevy_app: Option<String>,
|
pub bevy_app: Option<String>,
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
pub legion: Option<String>,
|
pub legion: Option<String>,
|
||||||
|
@ -25,6 +27,7 @@ pub struct Modules {
|
||||||
pub bevy_render: String,
|
pub bevy_render: String,
|
||||||
pub bevy_asset: String,
|
pub bevy_asset: String,
|
||||||
pub bevy_core: String,
|
pub bevy_core: String,
|
||||||
|
pub bevy_props: String,
|
||||||
pub bevy_app: String,
|
pub bevy_app: String,
|
||||||
pub legion: String,
|
pub legion: String,
|
||||||
}
|
}
|
||||||
|
@ -35,6 +38,7 @@ impl Modules {
|
||||||
bevy_asset: "bevy::asset".to_string(),
|
bevy_asset: "bevy::asset".to_string(),
|
||||||
bevy_render: "bevy::render".to_string(),
|
bevy_render: "bevy::render".to_string(),
|
||||||
bevy_core: "bevy::core".to_string(),
|
bevy_core: "bevy::core".to_string(),
|
||||||
|
bevy_props: "bevy::props".to_string(),
|
||||||
bevy_app: "bevy::app".to_string(),
|
bevy_app: "bevy::app".to_string(),
|
||||||
legion: "bevy".to_string(),
|
legion: "bevy".to_string(),
|
||||||
}
|
}
|
||||||
|
@ -45,6 +49,7 @@ impl Modules {
|
||||||
bevy_asset: "bevy_asset".to_string(),
|
bevy_asset: "bevy_asset".to_string(),
|
||||||
bevy_render: "bevy_render".to_string(),
|
bevy_render: "bevy_render".to_string(),
|
||||||
bevy_core: "bevy_core".to_string(),
|
bevy_core: "bevy_core".to_string(),
|
||||||
|
bevy_props: "bevy_props".to_string(),
|
||||||
bevy_app: "bevy_app".to_string(),
|
bevy_app: "bevy_app".to_string(),
|
||||||
legion: "legion".to_string(),
|
legion: "legion".to_string(),
|
||||||
}
|
}
|
||||||
|
@ -57,6 +62,7 @@ impl Default for ModuleAttributeArgs {
|
||||||
bevy_asset: None,
|
bevy_asset: None,
|
||||||
bevy_render: None,
|
bevy_render: None,
|
||||||
bevy_core: None,
|
bevy_core: None,
|
||||||
|
bevy_props: None,
|
||||||
bevy_app: None,
|
bevy_app: None,
|
||||||
legion: None,
|
legion: None,
|
||||||
meta: true,
|
meta: true,
|
||||||
|
|
|
@ -1,86 +1,170 @@
|
||||||
use serde::{ser::SerializeMap, Deserialize, Serialize};
|
use serde::{ser::SerializeMap, Deserialize, Serialize};
|
||||||
use std::{any::Any, collections::HashMap};
|
use std::{any::Any, collections::HashMap, borrow::Cow};
|
||||||
|
|
||||||
pub struct Test {
|
pub struct DynamicScene {
|
||||||
a: usize,
|
pub entities: Vec<SceneEntity>,
|
||||||
b: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Props for Test {
|
#[derive(Serialize, Deserialize)]
|
||||||
fn prop(&self, name: &str) -> Option<&dyn Prop> {
|
pub struct SceneEntity {
|
||||||
match name {
|
pub entity: u32,
|
||||||
"a" => Some(&self.a),
|
pub components: Vec<DynamicProperties>,
|
||||||
"b" => Some(&self.b),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Prop> {
|
|
||||||
match name {
|
|
||||||
"a" => Some(&mut self.a),
|
|
||||||
"b" => Some(&mut self.b),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn prop_names(&self) -> Vec<&str> {
|
|
||||||
static NAMES: &[&str] = &["a", "b"];
|
|
||||||
NAMES.to_vec()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DynamicProps {
|
pub struct DynamicProperties {
|
||||||
pub props: HashMap<String, Box<dyn Prop>>,
|
pub type_name: &'static str,
|
||||||
|
pub props: Vec<(Cow<'static, str>, Box<dyn Prop>)>,
|
||||||
|
pub prop_indices: HashMap<Cow<'static, str>, usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicProps {
|
pub struct SerializableProps<'a> {
|
||||||
|
pub props: &'a dyn Props,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynamicProperties {
|
||||||
|
fn push(&mut self, name: &str, prop: Box<dyn Prop>) {
|
||||||
|
let name: Cow<'static, str> = Cow::Owned(name.to_string());
|
||||||
|
self.props.push((name.clone(), prop));
|
||||||
|
self.prop_indices.insert(name, self.props.len());
|
||||||
|
}
|
||||||
pub fn set<T: Prop>(&mut self, name: &str, prop: T) {
|
pub fn set<T: Prop>(&mut self, name: &str, prop: T) {
|
||||||
self.props.insert(name.to_string(), Box::new(prop));
|
if let Some(index) = self.prop_indices.get(name) {
|
||||||
|
self.props[*index].1 = Box::new(prop);
|
||||||
|
} else {
|
||||||
|
self.push(name, Box::new(prop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn set_box(&mut self, name: &str, prop: Box<dyn Prop>) {
|
||||||
|
if let Some(index) = self.prop_indices.get(name) {
|
||||||
|
self.props[*index].1 = prop;
|
||||||
|
} else {
|
||||||
|
self.push(name, prop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Props for DynamicProps {
|
impl Props for DynamicProperties {
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
self.type_name
|
||||||
|
}
|
||||||
fn prop(&self, name: &str) -> Option<&dyn Prop> {
|
fn prop(&self, name: &str) -> Option<&dyn Prop> {
|
||||||
self.props.get(name).map(|p| &**p)
|
if let Some(index) = self.prop_indices.get(name) {
|
||||||
|
Some(&*self.props[*index].1)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Prop> {
|
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Prop> {
|
||||||
self.props.get_mut(name).map(|p| &mut **p)
|
if let Some(index) = self.prop_indices.get(name) {
|
||||||
|
Some(&mut *self.props[*index].1)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn prop_names(&self) -> Vec<&str> {
|
|
||||||
self.props.keys().map(|k| k.as_str()).collect::<Vec<&str>>()
|
fn prop_with_index(&self, index: usize) -> Option<&dyn Prop> {
|
||||||
|
self.props.get(index).map(|(_i, prop)| &**prop)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prop_with_index_mut(&mut self, index: usize) -> Option<&mut dyn Prop> {
|
||||||
|
self.props.get_mut(index).map(|(_i, prop)| &mut **prop)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prop_name(&self, index: usize) -> Option<&str> {
|
||||||
|
self.props.get(index).map(|(name, _)| name.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prop_len(&self) -> usize {
|
||||||
|
self.props.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter_props(&self) -> PropIter {
|
||||||
|
PropIter {
|
||||||
|
props: self,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for DynamicProps {
|
impl Serialize for DynamicProperties {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
let mut state = serializer.serialize_map(Some(self.props.len()))?;
|
let mut state = serializer.serialize_map(Some(self.props.len()))?;
|
||||||
for prop_name in self.prop_names() {
|
state.serialize_entry("type", self.type_name())?;
|
||||||
let prop = self.prop(prop_name).unwrap();
|
for (name, prop) in self.iter_props() {
|
||||||
state.serialize_entry(prop_name, prop)?;
|
state.serialize_entry(name, prop)?;
|
||||||
|
}
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Serialize for SerializableProps<'a> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let mut state = serializer.serialize_map(Some(self.props.prop_len()))?;
|
||||||
|
state.serialize_entry("type", self.props.type_name())?;
|
||||||
|
for (name, prop) in self.props.iter_props() {
|
||||||
|
state.serialize_entry(name, prop)?;
|
||||||
}
|
}
|
||||||
state.end()
|
state.end()
|
||||||
// let mut state = serializer.serialize_struct("dyn", self.props.len())?;
|
|
||||||
// {
|
|
||||||
// for prop_name in self.prop_names() {
|
|
||||||
// let prop = self.prop(prop_name).unwrap();
|
|
||||||
// state.serialize_field(strrr, prop)?;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// state.end()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Props {
|
pub trait Props {
|
||||||
|
fn type_name(&self) -> &str;
|
||||||
fn prop(&self, name: &str) -> Option<&dyn Prop>;
|
fn prop(&self, name: &str) -> Option<&dyn Prop>;
|
||||||
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Prop>;
|
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Prop>;
|
||||||
fn prop_names(&self) -> Vec<&str>;
|
fn prop_with_index(&self, index: usize) -> Option<&dyn Prop>;
|
||||||
|
fn prop_with_index_mut(&mut self, index: usize) -> Option<&mut dyn Prop>;
|
||||||
|
fn prop_name(&self, index: usize) -> Option<&str>;
|
||||||
|
fn prop_len(&self) -> usize;
|
||||||
|
fn iter_props(&self) -> PropIter;
|
||||||
fn apply(&mut self, props: &dyn Props) {
|
fn apply(&mut self, props: &dyn Props) {
|
||||||
for prop_name in props.prop_names() {
|
for (name, prop) in props.iter_props() {
|
||||||
self.prop_mut(prop_name)
|
self.prop_mut(name).unwrap().set_val_dyn(prop);
|
||||||
.unwrap()
|
}
|
||||||
.set_prop_val(props.prop(prop_name).unwrap().clone());
|
}
|
||||||
|
fn to_dynamic(&self) -> DynamicProperties where Self: 'static {
|
||||||
|
let mut dynamic_props = DynamicProperties::default();
|
||||||
|
for (name, prop) in self.iter_props() {
|
||||||
|
dynamic_props.set_box(name, prop.clone_prop());
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic_props.type_name = std::any::type_name::<Self>();
|
||||||
|
dynamic_props
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PropIter<'a> {
|
||||||
|
props: &'a dyn Props,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PropIter<'a> {
|
||||||
|
pub fn new(props: &'a dyn Props) -> Self {
|
||||||
|
PropIter {
|
||||||
|
props,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for PropIter<'a> {
|
||||||
|
type Item = (&'a str, &'a dyn Prop);
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.index < self.props.prop_len() {
|
||||||
|
let prop = self.props.prop_with_index(self.index).unwrap();
|
||||||
|
let name = self.props.prop_name(self.index).unwrap();
|
||||||
|
self.index += 1;
|
||||||
|
Some((name, prop))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,42 +172,63 @@ pub trait Props {
|
||||||
pub trait Prop: erased_serde::Serialize + Send + Sync + Any + 'static {
|
pub trait Prop: erased_serde::Serialize + Send + Sync + Any + 'static {
|
||||||
fn any(&self) -> &dyn Any;
|
fn any(&self) -> &dyn Any;
|
||||||
fn any_mut(&mut self) -> &mut dyn Any;
|
fn any_mut(&mut self) -> &mut dyn Any;
|
||||||
fn clone(&self) -> Box<dyn Any>;
|
fn clone_prop(&self) -> Box<dyn Prop>;
|
||||||
fn type_name(&self) -> &str {
|
fn set_val_dyn(&mut self, value: &dyn Prop);
|
||||||
std::any::type_name::<Self>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
erased_serde::serialize_trait_object!(Prop);
|
erased_serde::serialize_trait_object!(Prop);
|
||||||
|
|
||||||
pub trait PropVal {
|
pub trait PropVal {
|
||||||
fn prop_val<T: 'static>(&self) -> Option<&T>;
|
fn val<T: 'static>(&self) -> Option<&T>;
|
||||||
fn set_prop_val<T: 'static>(&mut self, value: T);
|
fn set_val<T: 'static>(&mut self, value: T);
|
||||||
fn set_prop_val_boxed<T: 'static>(&mut self, value: Box<dyn Any>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait PropsVal {
|
||||||
|
fn prop_val<T: 'static>(&self, name: &str) -> Option<&T>;
|
||||||
|
fn set_prop_val<T: 'static>(&mut self, name: &str, value: T);
|
||||||
|
fn set_prop_val_dyn<T: 'static>(&mut self, name: &str, value: &dyn Prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl PropVal for dyn Prop {
|
impl PropVal for dyn Prop {
|
||||||
fn prop_val<T: 'static>(&self) -> Option<&T> {
|
fn val<T: 'static>(&self) -> Option<&T> {
|
||||||
self.any().downcast_ref::<T>()
|
self.any().downcast_ref::<T>()
|
||||||
}
|
}
|
||||||
fn set_prop_val<T: 'static>(&mut self, value: T) {
|
fn set_val<T: 'static>(&mut self, value: T) {
|
||||||
if let Some(prop) = self.any_mut().downcast_mut::<T>() {
|
if let Some(prop) = self.any_mut().downcast_mut::<T>() {
|
||||||
*prop = value;
|
*prop = value;
|
||||||
}
|
} else {
|
||||||
}
|
panic!("prop value is not {}", std::any::type_name::<T>());
|
||||||
fn set_prop_val_boxed<T: 'static>(&mut self, value: Box<dyn Any>) {
|
|
||||||
if let Some(prop) = self.any_mut().downcast_mut::<T>() {
|
|
||||||
*prop = *value.downcast::<T>().unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deserialize<'a> for DynamicProps {
|
impl<P> PropsVal for P where P: Props {
|
||||||
|
fn prop_val<T: 'static>(&self, name: &str) -> Option<&T> {
|
||||||
|
self.prop(name).and_then(|p| p.any().downcast_ref::<T>())
|
||||||
|
}
|
||||||
|
fn set_prop_val<T: 'static>(&mut self, name: &str, value: T) {
|
||||||
|
if let Some(prop) = self.prop_mut(name).and_then(|p| p.any_mut().downcast_mut::<T>()) {
|
||||||
|
*prop = value;
|
||||||
|
} else {
|
||||||
|
panic!("prop does not exist or is incorrect type: {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn set_prop_val_dyn<T: 'static>(&mut self, name: &str, value: &dyn Prop) {
|
||||||
|
if let Some(prop) = self.prop_mut(name) {
|
||||||
|
prop.set_val_dyn(value);
|
||||||
|
} else {
|
||||||
|
panic!("prop does not exist: {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deserialize<'a> for DynamicProperties {
|
||||||
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'a>,
|
D: serde::Deserializer<'a>,
|
||||||
{
|
{
|
||||||
Ok(DynamicProps::default())
|
Ok(DynamicProperties::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +242,14 @@ where
|
||||||
fn any_mut(&mut self) -> &mut dyn Any {
|
fn any_mut(&mut self) -> &mut dyn Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
fn clone(&self) -> Box<dyn Any> {
|
fn clone_prop(&self) -> Box<dyn Prop> {
|
||||||
Box::new(self.clone())
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
|
fn set_val_dyn(&mut self, value: &dyn Prop) {
|
||||||
|
if let Some(prop) = value.any().downcast_ref::<T>() {
|
||||||
|
*self = prop.clone();
|
||||||
|
} else {
|
||||||
|
panic!("prop value is not {}", std::any::type_name::<T>());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
56
examples/scene/props.rs
Normal file
56
examples/scene/props.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_props::{DynamicScene, SerializableProps, SceneEntity};
|
||||||
|
use serde::ser::Serialize;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::build()
|
||||||
|
.add_default_plugins()
|
||||||
|
.add_startup_system(setup.system())
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties)]
|
||||||
|
pub struct Test {
|
||||||
|
a: usize,
|
||||||
|
b: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup() {
|
||||||
|
let mut test = Test {
|
||||||
|
a: 1,
|
||||||
|
b: "hi".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
test.set_prop_val::<usize>("a", 2);
|
||||||
|
assert_eq!(test.a, 2);
|
||||||
|
|
||||||
|
let mut patch = DynamicProperties::default();
|
||||||
|
patch.set::<usize>("a", 3);
|
||||||
|
test.apply(&patch);
|
||||||
|
|
||||||
|
assert_eq!(test.a, 3);
|
||||||
|
|
||||||
|
|
||||||
|
let ser = SerializableProps {
|
||||||
|
props: &test,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut serializer = ron::ser::Serializer::new(Some(ron::ser::PrettyConfig::default()), false);
|
||||||
|
ser.serialize(&mut serializer).unwrap();
|
||||||
|
println!("{}", serializer.into_output_string());
|
||||||
|
|
||||||
|
let dynamic_scene = DynamicScene {
|
||||||
|
entities: vec![
|
||||||
|
SceneEntity {
|
||||||
|
entity: 12345,
|
||||||
|
components: vec![
|
||||||
|
patch
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut serializer = ron::ser::Serializer::new(Some(ron::ser::PrettyConfig::default()), false);
|
||||||
|
dynamic_scene.entities.serialize(&mut serializer).unwrap();
|
||||||
|
println!("{}", serializer.into_output_string());
|
||||||
|
}
|
|
@ -11,6 +11,8 @@ pub use crate::derive::*;
|
||||||
pub use crate::diagnostic::DiagnosticsPlugin;
|
pub use crate::diagnostic::DiagnosticsPlugin;
|
||||||
#[cfg(feature = "pbr")]
|
#[cfg(feature = "pbr")]
|
||||||
pub use crate::pbr::{entity::*, light::Light, material::StandardMaterial};
|
pub use crate::pbr::{entity::*, light::Light, material::StandardMaterial};
|
||||||
|
#[cfg(feature = "props")]
|
||||||
|
pub use crate::props::{Prop, Props, PropVal, PropsVal, DynamicProperties};
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
pub use crate::render::{
|
pub use crate::render::{
|
||||||
draw_target,
|
draw_target,
|
||||||
|
|
Loading…
Reference in a new issue