mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
scenes: deserialization and refactor
This commit is contained in:
parent
553b754492
commit
d920100d35
30 changed files with 822 additions and 247 deletions
|
@ -2,10 +2,11 @@
|
|||
|
||||
## Adapted Code
|
||||
|
||||
* legion
|
||||
* legion_transform
|
||||
* wgpu-rs examples
|
||||
|
||||
## Insipration
|
||||
## Inspiration
|
||||
|
||||
* amethyst
|
||||
* coffee
|
16
Cargo.toml
16
Cargo.toml
|
@ -6,7 +6,7 @@ edition = "2018"
|
|||
|
||||
[features]
|
||||
default = ["headless", "wgpu", "winit"]
|
||||
headless = ["asset", "core", "derive", "diagnostic", "gltf", "input", "pbr", "render", "serialization", "text", "transform", "ui", "window"]
|
||||
headless = ["asset", "core", "derive", "diagnostic", "gltf", "input", "pbr", "props", "render", "scene", "text", "transform", "ui", "window"]
|
||||
asset = ["bevy_asset"]
|
||||
core = ["bevy_core"]
|
||||
derive = ["bevy_derive"]
|
||||
|
@ -14,8 +14,9 @@ diagnostic = ["bevy_diagnostic"]
|
|||
gltf = ["bevy_gltf"]
|
||||
input = ["bevy_input"]
|
||||
pbr = ["bevy_pbr"]
|
||||
props = ["bevy_props"]
|
||||
render = ["bevy_render"]
|
||||
serialization = ["bevy_serialization"]
|
||||
scene = ["bevy_scene"]
|
||||
text = ["bevy_text"]
|
||||
transform = ["bevy_transform"]
|
||||
ui = ["bevy_ui"]
|
||||
|
@ -40,8 +41,9 @@ bevy_diagnostic = { path = "crates/bevy_diagnostic", optional = true }
|
|||
bevy_gltf = { path = "crates/bevy_gltf", optional = true }
|
||||
bevy_input = { path = "crates/bevy_input", optional = true }
|
||||
bevy_pbr = { path = "crates/bevy_pbr", optional = true }
|
||||
bevy_props = { path = "crates/bevy_props", optional = true }
|
||||
bevy_render = { path = "crates/bevy_render", optional = true }
|
||||
bevy_serialization = { path = "crates/bevy_serialization", optional = true }
|
||||
bevy_scene = { path = "crates/bevy_scene", optional = true }
|
||||
bevy_transform = { path = "crates/bevy_transform", optional = true }
|
||||
bevy_text = { path = "crates/bevy_text", optional = true }
|
||||
bevy_ui = { path = "crates/bevy_ui", optional = true }
|
||||
|
@ -80,8 +82,8 @@ name = "parenting"
|
|||
path = "examples/3d/parenting.rs"
|
||||
|
||||
[[example]]
|
||||
name = "scene"
|
||||
path = "examples/3d/scene.rs"
|
||||
name = "3d_scene"
|
||||
path = "examples/3d/3d_scene.rs"
|
||||
|
||||
[[example]]
|
||||
name = "spawner"
|
||||
|
@ -148,8 +150,8 @@ name = "input_keyboard"
|
|||
path = "examples/input/input_keyboard.rs"
|
||||
|
||||
[[example]]
|
||||
name = "serializing"
|
||||
path = "examples/serializing/serializing.rs"
|
||||
name = "load_scene"
|
||||
path = "examples/scene/load_scene.rs"
|
||||
|
||||
[[example]]
|
||||
name = "shader_custom_material"
|
||||
|
|
32
assets/scene/load_scene_example.scn
Normal file
32
assets/scene/load_scene_example.scn
Normal file
|
@ -0,0 +1,32 @@
|
|||
[
|
||||
(
|
||||
id: 2309003120,
|
||||
components: [
|
||||
(
|
||||
type: "Test",
|
||||
data: (
|
||||
x: 3,
|
||||
y: 4,
|
||||
),
|
||||
),
|
||||
(
|
||||
type: "Foo",
|
||||
data: (
|
||||
value: "hi",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
id: 4238063392,
|
||||
components: [
|
||||
(
|
||||
type: "Test",
|
||||
data: (
|
||||
x: 3,
|
||||
y: 4,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -7,4 +7,6 @@ edition = "2018"
|
|||
[dependencies]
|
||||
legion = { path = "../bevy_legion", features = ["serialize"] }
|
||||
libloading = "0.5.2"
|
||||
log = { version = "0.4", features = ["release_max_level_info"] }
|
||||
log = { version = "0.4", features = ["release_max_level_info"] }
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
erased-serde = "0.3"
|
|
@ -5,10 +5,10 @@ mod entity_archetype;
|
|||
mod event;
|
||||
mod plugin;
|
||||
mod resources;
|
||||
mod system;
|
||||
pub mod schedule_plan;
|
||||
pub mod schedule_runner;
|
||||
pub mod stage;
|
||||
mod system;
|
||||
|
||||
pub use app::*;
|
||||
pub use app_builder::*;
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
update_asset_storage_system, AssetChannel, AssetLoader, AssetServer, ChannelAssetHandler,
|
||||
Handle, HandleId,
|
||||
};
|
||||
use bevy_app::{AppBuilder, Events};
|
||||
use bevy_app::{AppBuilder, Events, FromResources};
|
||||
use bevy_core::bytes::GetBytes;
|
||||
use legion::prelude::*;
|
||||
use std::{
|
||||
|
@ -134,9 +134,9 @@ pub trait AddAsset {
|
|||
fn add_asset<T>(&mut self) -> &mut Self
|
||||
where
|
||||
T: Send + Sync + 'static;
|
||||
fn add_asset_loader<TLoader, TAsset>(&mut self, loader: TLoader) -> &mut Self
|
||||
fn add_asset_loader<TAsset, TLoader>(&mut self) -> &mut Self
|
||||
where
|
||||
TLoader: AssetLoader<TAsset> + Clone,
|
||||
TLoader: AssetLoader<TAsset> + FromResources,
|
||||
TAsset: Send + Sync + 'static;
|
||||
}
|
||||
|
||||
|
@ -153,9 +153,9 @@ impl AddAsset for AppBuilder {
|
|||
.add_event::<AssetEvent<T>>()
|
||||
}
|
||||
|
||||
fn add_asset_loader<TLoader, TAsset>(&mut self, loader: TLoader) -> &mut Self
|
||||
fn add_asset_loader<TAsset, TLoader>(&mut self) -> &mut Self
|
||||
where
|
||||
TLoader: AssetLoader<TAsset> + Clone,
|
||||
TLoader: AssetLoader<TAsset> + FromResources,
|
||||
TAsset: Send + Sync + 'static,
|
||||
{
|
||||
{
|
||||
|
@ -174,8 +174,8 @@ impl AddAsset for AppBuilder {
|
|||
.resources()
|
||||
.get_mut::<AssetServer>()
|
||||
.expect("AssetServer does not exist. Consider adding it as a resource.");
|
||||
asset_server.add_loader(loader.clone());
|
||||
let handler = ChannelAssetHandler::new(loader, asset_channel.sender.clone());
|
||||
asset_server.add_loader(TLoader::from_resources(self.resources()));
|
||||
let handler = ChannelAssetHandler::new(TLoader::from_resources(self.resources()), asset_channel.sender.clone());
|
||||
asset_server.add_handler(handler);
|
||||
}
|
||||
self
|
||||
|
|
|
@ -3,12 +3,13 @@ pub use loader::*;
|
|||
|
||||
use bevy_app::{AppBuilder, AppPlugin};
|
||||
use bevy_asset::AddAsset;
|
||||
use bevy_render::mesh::Mesh;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GltfPlugin;
|
||||
|
||||
impl AppPlugin for GltfPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
app.add_asset_loader(GltfLoader);
|
||||
app.add_asset_loader::<Mesh, GltfLoader>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use gltf::{buffer::Source, iter, mesh::Mode};
|
|||
use std::{fs, io, path::Path};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Default)]
|
||||
pub struct GltfLoader;
|
||||
|
||||
impl AssetLoader<Mesh> for GltfLoader {
|
||||
|
|
|
@ -264,11 +264,12 @@ impl GuidEntityAllocator {
|
|||
|
||||
/// Allocates a new unused `Entity` ID.
|
||||
pub fn create_entity(&self) -> Entity {
|
||||
if !self.next_ids.read().is_empty() {
|
||||
return self.next_ids.write().pop().unwrap();
|
||||
}
|
||||
let entity = if !self.next_ids.read().is_empty() {
|
||||
self.next_ids.write().pop().unwrap()
|
||||
} else {
|
||||
Entity::new(rand::random::<u32>(), Wrapping(1))
|
||||
};
|
||||
|
||||
let entity = Entity::new(rand::random::<u32>(), Wrapping(1));
|
||||
self.entities.write().insert(entity);
|
||||
entity
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ impl WorldId {
|
|||
pub struct World {
|
||||
id: WorldId,
|
||||
storage: UnsafeCell<Storage>,
|
||||
pub(crate) entity_allocator: Arc<GuidEntityAllocator>,
|
||||
pub entity_allocator: Arc<GuidEntityAllocator>,
|
||||
entity_locations: Locations,
|
||||
defrag_progress: usize,
|
||||
command_buffer_size: usize,
|
||||
|
|
11
crates/bevy_props/Cargo.toml
Normal file
11
crates/bevy_props/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "bevy_props"
|
||||
version = "0.1.0"
|
||||
authors = ["Carter Anderson <mcanders1@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = "1"
|
||||
erased-serde = "0.3"
|
143
crates/bevy_props/src/lib.rs
Normal file
143
crates/bevy_props/src/lib.rs
Normal file
|
@ -0,0 +1,143 @@
|
|||
use serde::{ser::SerializeMap, Deserialize, Serialize};
|
||||
use std::{any::Any, collections::HashMap};
|
||||
|
||||
pub struct Test {
|
||||
a: usize,
|
||||
b: String,
|
||||
}
|
||||
|
||||
impl Props for Test {
|
||||
fn prop(&self, name: &str) -> Option<&dyn Prop> {
|
||||
match name {
|
||||
"a" => Some(&self.a),
|
||||
"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)]
|
||||
pub struct DynamicProps {
|
||||
pub props: HashMap<String, Box<dyn Prop>>,
|
||||
}
|
||||
|
||||
impl DynamicProps {
|
||||
pub fn set<T: Prop>(&mut self, name: &str, prop: T) {
|
||||
self.props.insert(name.to_string(), Box::new(prop));
|
||||
}
|
||||
}
|
||||
|
||||
impl Props for DynamicProps {
|
||||
fn prop(&self, name: &str) -> Option<&dyn Prop> {
|
||||
self.props.get(name).map(|p| &**p)
|
||||
}
|
||||
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Prop> {
|
||||
self.props.get_mut(name).map(|p| &mut **p)
|
||||
}
|
||||
fn prop_names(&self) -> Vec<&str> {
|
||||
self.props.keys().map(|k| k.as_str()).collect::<Vec<&str>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for DynamicProps {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_map(Some(self.props.len()))?;
|
||||
for prop_name in self.prop_names() {
|
||||
let prop = self.prop(prop_name).unwrap();
|
||||
state.serialize_entry(prop_name, prop)?;
|
||||
}
|
||||
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 {
|
||||
fn prop(&self, name: &str) -> Option<&dyn Prop>;
|
||||
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Prop>;
|
||||
fn prop_names(&self) -> Vec<&str>;
|
||||
fn apply(&mut self, props: &dyn Props) {
|
||||
for prop_name in props.prop_names() {
|
||||
self.prop_mut(prop_name)
|
||||
.unwrap()
|
||||
.set_prop_val(props.prop(prop_name).unwrap().clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Prop: erased_serde::Serialize + Send + Sync + Any + 'static {
|
||||
fn any(&self) -> &dyn Any;
|
||||
fn any_mut(&mut self) -> &mut dyn Any;
|
||||
fn clone(&self) -> Box<dyn Any>;
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
erased_serde::serialize_trait_object!(Prop);
|
||||
|
||||
pub trait PropVal {
|
||||
fn prop_val<T: 'static>(&self) -> Option<&T>;
|
||||
fn set_prop_val<T: 'static>(&mut self, value: T);
|
||||
fn set_prop_val_boxed<T: 'static>(&mut self, value: Box<dyn Any>);
|
||||
}
|
||||
|
||||
impl PropVal for dyn Prop {
|
||||
fn prop_val<T: 'static>(&self) -> Option<&T> {
|
||||
self.any().downcast_ref::<T>()
|
||||
}
|
||||
fn set_prop_val<T: 'static>(&mut self, value: T) {
|
||||
if let Some(prop) = self.any_mut().downcast_mut::<T>() {
|
||||
*prop = value;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'a>,
|
||||
{
|
||||
Ok(DynamicProps::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Prop for T
|
||||
where
|
||||
T: Clone + Serialize + Send + Sync + Any + 'static,
|
||||
{
|
||||
fn any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
fn clone(&self) -> Box<dyn Any> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
|
@ -72,7 +72,7 @@ impl AppPlugin for RenderPlugin {
|
|||
.add_asset::<Texture>()
|
||||
.add_asset::<Shader>()
|
||||
.add_asset::<PipelineDescriptor>()
|
||||
.add_asset_loader(PngTextureLoader::default())
|
||||
.add_asset_loader::<Texture, PngTextureLoader>()
|
||||
.init_resource::<RenderGraph>()
|
||||
.init_resource::<PipelineAssignments>()
|
||||
.init_resource::<PipelineCompiler>()
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
[package]
|
||||
name = "bevy_serialization"
|
||||
name = "bevy_scene"
|
||||
version = "0.1.0"
|
||||
authors = ["Carter Anderson <mcanders1@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
bevy_app = { path = "../bevy_app" }
|
||||
bevy_asset = { path = "../bevy_asset" }
|
||||
legion = { path = "../bevy_legion", features = ["serialize"] }
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
erased-serde = "0.3"
|
||||
type-uuid = "0.1"
|
||||
ron = "0.5.1"
|
||||
uuid = { version = "0.8", features = ["v4", "serde"] }
|
||||
uuid = { version = "0.8", features = ["v4", "serde"] }
|
||||
anyhow = "1.0"
|
124
crates/bevy_scene/src/component_registry.rs
Normal file
124
crates/bevy_scene/src/component_registry.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
use bevy_app::AppBuilder;
|
||||
use legion::{
|
||||
prelude::{Entity, World},
|
||||
storage::{ArchetypeDescription, ComponentResourceSet, ComponentTypeId},
|
||||
};
|
||||
use serde::{de::DeserializeSeed, ser::Serialize, Deserialize};
|
||||
use std::{collections::HashMap, marker::PhantomData, ptr::NonNull, sync::{RwLock, Arc}};
|
||||
use crate::world::ComponentSeqDeserializer;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ComponentRegistryContext {
|
||||
pub value: Arc<RwLock<ComponentRegistry>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ComponentRegistry {
|
||||
pub registrations: HashMap<ComponentTypeId, ComponentRegistration>,
|
||||
pub short_names: HashMap<String, ComponentTypeId>,
|
||||
pub full_names: HashMap<String, ComponentTypeId>,
|
||||
}
|
||||
|
||||
impl ComponentRegistry {
|
||||
pub fn register<T>(&mut self)
|
||||
where
|
||||
T: Send + Sync + 'static + Serialize + for<'de> Deserialize<'de>,
|
||||
{
|
||||
let registration = ComponentRegistration::of::<T>();
|
||||
self.short_names
|
||||
.insert(registration.short_name.to_string(), registration.ty);
|
||||
self.full_names
|
||||
.insert(registration.ty.0.to_string(), registration.ty);
|
||||
self.registrations.insert(registration.ty, registration);
|
||||
}
|
||||
|
||||
pub fn get(&self, type_id: &ComponentTypeId) -> Option<&ComponentRegistration> {
|
||||
self.registrations.get(type_id)
|
||||
}
|
||||
|
||||
pub fn get_with_full_name(&self, full_name: &str) -> Option<&ComponentRegistration> {
|
||||
self.full_names
|
||||
.get(full_name)
|
||||
.and_then(|id| self.registrations.get(id))
|
||||
}
|
||||
|
||||
pub fn get_with_short_name(&self, short_name: &str) -> Option<&ComponentRegistration> {
|
||||
self.short_names
|
||||
.get(short_name)
|
||||
.and_then(|id| self.registrations.get(id))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComponentRegistration {
|
||||
pub ty: ComponentTypeId,
|
||||
pub comp_serialize_fn: fn(&ComponentResourceSet, &mut dyn FnMut(&dyn erased_serde::Serialize)),
|
||||
pub individual_comp_serialize_fn:
|
||||
fn(&ComponentResourceSet, usize, &mut dyn FnMut(&dyn erased_serde::Serialize)),
|
||||
pub comp_deserialize_fn: fn(
|
||||
deserializer: &mut dyn erased_serde::Deserializer,
|
||||
get_next_storage_fn: &mut dyn FnMut() -> Option<(NonNull<u8>, usize)>,
|
||||
) -> Result<(), erased_serde::Error>,
|
||||
pub individual_comp_deserialize_fn: fn(
|
||||
deserializer: &mut dyn erased_serde::Deserializer,
|
||||
&mut World,
|
||||
Entity,
|
||||
) -> Result<(), erased_serde::Error>,
|
||||
pub register_comp_fn: fn(&mut ArchetypeDescription),
|
||||
pub short_name: &'static str,
|
||||
}
|
||||
|
||||
impl ComponentRegistration {
|
||||
pub fn of<T: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static>() -> Self {
|
||||
let ty = ComponentTypeId::of::<T>();
|
||||
Self {
|
||||
ty,
|
||||
comp_serialize_fn: |comp_storage, serialize_fn| {
|
||||
// it's safe because we know this is the correct type due to lookup
|
||||
let slice = unsafe { comp_storage.data_slice::<T>() };
|
||||
serialize_fn(&*slice);
|
||||
},
|
||||
individual_comp_serialize_fn: |comp_storage, index: usize, serialize_fn| {
|
||||
// it's safe because we know this is the correct type due to lookup
|
||||
let slice = unsafe { comp_storage.data_slice::<T>() };
|
||||
serialize_fn(&slice[index]);
|
||||
},
|
||||
comp_deserialize_fn: |deserializer, get_next_storage_fn| {
|
||||
let comp_seq_deser = ComponentSeqDeserializer::<T> {
|
||||
get_next_storage_fn,
|
||||
_marker: PhantomData,
|
||||
};
|
||||
comp_seq_deser.deserialize(deserializer)?;
|
||||
Ok(())
|
||||
},
|
||||
individual_comp_deserialize_fn: |deserializer, world, entity| {
|
||||
let component = erased_serde::deserialize::<T>(deserializer)?;
|
||||
world.add_component(entity, component).unwrap();
|
||||
Ok(())
|
||||
},
|
||||
register_comp_fn: |desc| {
|
||||
desc.register_component::<T>();
|
||||
},
|
||||
short_name: ty.0.split("::").last().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RegisterComponent {
|
||||
fn register_component<T>(&mut self) -> &mut Self
|
||||
where
|
||||
T: Send + Sync + 'static + Serialize + for<'de> Deserialize<'de>;
|
||||
}
|
||||
|
||||
impl RegisterComponent for AppBuilder {
|
||||
fn register_component<T>(&mut self) -> &mut Self
|
||||
where
|
||||
T: Send + Sync + 'static + Serialize + for<'de> Deserialize<'de>,
|
||||
{
|
||||
{
|
||||
let registry_context = self.resources().get_mut::<ComponentRegistryContext>().unwrap();
|
||||
registry_context.value.write().unwrap().register::<T>();
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
28
crates/bevy_scene/src/lib.rs
Normal file
28
crates/bevy_scene/src/lib.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
mod component_registry;
|
||||
mod scene;
|
||||
mod serde;
|
||||
pub use crate::serde::*;
|
||||
pub use component_registry::*;
|
||||
pub use scene::*;
|
||||
|
||||
use bevy_app::{AppBuilder, AppPlugin};
|
||||
use bevy_asset::AddAsset;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ComponentRegistryPlugin;
|
||||
|
||||
impl AppPlugin for ComponentRegistryPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
app.init_resource::<ComponentRegistryContext>();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ScenePlugin;
|
||||
|
||||
impl AppPlugin for ScenePlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
app.add_asset::<Scene>()
|
||||
.add_asset_loader::<Scene, SceneLoader>();
|
||||
}
|
||||
}
|
49
crates/bevy_scene/src/scene.rs
Normal file
49
crates/bevy_scene/src/scene.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use crate::{ComponentRegistry, ComponentRegistryContext, SceneDeserializer};
|
||||
use anyhow::Result;
|
||||
use bevy_app::FromResources;
|
||||
use bevy_asset::AssetLoader;
|
||||
use legion::prelude::{Resources, World};
|
||||
use serde::de::DeserializeSeed;
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Scene {
|
||||
pub world: World,
|
||||
}
|
||||
|
||||
pub struct SceneLoader {
|
||||
component_registry: Arc<RwLock<ComponentRegistry>>,
|
||||
}
|
||||
|
||||
impl FromResources for SceneLoader {
|
||||
fn from_resources(resources: &Resources) -> Self {
|
||||
let component_registry = resources
|
||||
.get::<ComponentRegistryContext>()
|
||||
.expect("SceneLoader requires the ComponentRegistry resource.");
|
||||
SceneLoader {
|
||||
component_registry: component_registry.value.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssetLoader<Scene> for SceneLoader {
|
||||
fn from_bytes(&self, _asset_path: &Path, bytes: Vec<u8>) -> Result<Scene> {
|
||||
let mut deserializer = ron::de::Deserializer::from_bytes(&bytes).unwrap();
|
||||
let mut scene = Scene::default();
|
||||
let scene_deserializer = SceneDeserializer {
|
||||
component_registry: &self.component_registry.read().unwrap(),
|
||||
scene: &mut scene,
|
||||
};
|
||||
|
||||
scene_deserializer.deserialize(&mut deserializer).unwrap();
|
||||
|
||||
Ok(scene)
|
||||
}
|
||||
fn extensions(&self) -> &[&str] {
|
||||
static EXTENSIONS: &[&str] = &["scn"];
|
||||
EXTENSIONS
|
||||
}
|
||||
}
|
6
crates/bevy_scene/src/serde/mod.rs
Normal file
6
crates/bevy_scene/src/serde/mod.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
mod scene_de;
|
||||
mod scene_ser;
|
||||
pub mod world;
|
||||
|
||||
pub use scene_de::*;
|
||||
pub use scene_ser::*;
|
288
crates/bevy_scene/src/serde/scene_de.rs
Normal file
288
crates/bevy_scene/src/serde/scene_de.rs
Normal file
|
@ -0,0 +1,288 @@
|
|||
use crate::{ComponentRegistration, ComponentRegistry, Scene};
|
||||
use legion::prelude::{Entity, World};
|
||||
use serde::{
|
||||
de::{DeserializeSeed, Error, MapAccess, SeqAccess, Visitor},
|
||||
Deserialize,
|
||||
};
|
||||
use std::num::Wrapping;
|
||||
|
||||
pub struct SceneDeserializer<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub scene: &'a mut Scene,
|
||||
}
|
||||
|
||||
impl<'de> DeserializeSeed<'de> for SceneDeserializer<'de> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_seq(EntitySeqVisiter {
|
||||
world: &mut self.scene.world,
|
||||
component_registry: &self.component_registry,
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct EntitySeqVisiter<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
}
|
||||
|
||||
impl<'a, 'de> Visitor<'de> for EntitySeqVisiter<'a> {
|
||||
type Value = ();
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("list of entities")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
while let Some(()) = seq.next_element_seed(EntityDeserializer {
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
})? {}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct EntityDeserializer<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
}
|
||||
|
||||
|
||||
pub const ENTITY_FIELD_ID: &str = "id";
|
||||
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
|
||||
|
||||
impl<'a, 'de> DeserializeSeed<'de> for EntityDeserializer<'a> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_struct(
|
||||
"Entity",
|
||||
&[ENTITY_FIELD_ID, ENTITY_FIELD_COMPONENTS],
|
||||
EntityVisiter {
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct EntityVisiter<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
}
|
||||
|
||||
impl<'a, 'de> Visitor<'de> for EntityVisiter<'a> {
|
||||
type Value = ();
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("entity struct")
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut map: V) -> Result<(), V::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
{
|
||||
let mut entity = None;
|
||||
let mut components = false;
|
||||
while let Some(key) = map.next_key()? {
|
||||
match key {
|
||||
EntityField::Id => {
|
||||
if entity.is_some() {
|
||||
return Err(Error::duplicate_field(ENTITY_FIELD_ID));
|
||||
}
|
||||
let id = map.next_value()?;
|
||||
self.world
|
||||
.entity_allocator
|
||||
.push_next_ids((&[Entity::new(id, Wrapping(1))]).iter().map(|e| (*e)));
|
||||
entity = Some(self.world.insert((), vec![()])[0]);
|
||||
}
|
||||
EntityField::Components => {
|
||||
if components {
|
||||
return Err(Error::duplicate_field(ENTITY_FIELD_COMPONENTS));
|
||||
}
|
||||
|
||||
let entity = entity.ok_or_else(|| Error::missing_field(ENTITY_FIELD_ID))?;
|
||||
// this is just a placeholder value to protect against duplicates
|
||||
components = true;
|
||||
map.next_value_seed(ComponentSeqDeserializer {
|
||||
entity,
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(field_identifier, rename_all = "lowercase")]
|
||||
enum EntityField {
|
||||
Id,
|
||||
Components,
|
||||
}
|
||||
|
||||
struct ComponentSeqDeserializer<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
impl<'a, 'de> DeserializeSeed<'de> for ComponentSeqDeserializer<'a> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_seq(ComponentSeqVisiter {
|
||||
entity: self.entity,
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct ComponentSeqVisiter<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
impl<'a, 'de> Visitor<'de> for ComponentSeqVisiter<'a> {
|
||||
type Value = ();
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("list of components")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
while let Some(()) = seq.next_element_seed(ComponentDeserializer {
|
||||
entity: self.entity,
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
})? {}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
struct ComponentDeserializer<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
impl<'a, 'de> DeserializeSeed<'de> for ComponentDeserializer<'a> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_struct(
|
||||
"Component",
|
||||
&[COMPONENT_FIELD_TYPE, COMPONENT_FIELD_DATA],
|
||||
ComponentVisiter {
|
||||
entity: self.entity,
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(field_identifier, rename_all = "lowercase")]
|
||||
enum ComponentField {
|
||||
Type,
|
||||
Data,
|
||||
}
|
||||
|
||||
pub const COMPONENT_FIELD_TYPE: &str = "type";
|
||||
pub const COMPONENT_FIELD_DATA: &str = "data";
|
||||
|
||||
struct ComponentVisiter<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
impl<'a, 'de> Visitor<'de> for ComponentVisiter<'a> {
|
||||
type Value = ();
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("component")
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut map: V) -> Result<(), V::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
{
|
||||
let mut component_type = None;
|
||||
let mut component_data = false;
|
||||
while let Some(key) = map.next_key()? {
|
||||
match key {
|
||||
ComponentField::Type => {
|
||||
if component_type.is_some() {
|
||||
return Err(Error::duplicate_field(COMPONENT_FIELD_TYPE));
|
||||
}
|
||||
component_type = Some(map.next_value::<String>()?);
|
||||
}
|
||||
ComponentField::Data => {
|
||||
if component_data {
|
||||
return Err(Error::duplicate_field(COMPONENT_FIELD_DATA));
|
||||
}
|
||||
|
||||
let component_type = component_type
|
||||
.as_ref()
|
||||
.ok_or_else(|| Error::missing_field(COMPONENT_FIELD_TYPE))?;
|
||||
let component_registration = self
|
||||
.component_registry
|
||||
.get_with_short_name(component_type)
|
||||
.ok_or_else(|| Error::custom(format!("Component '{}' has not been registered. Consider registering it with AppBuilder::register_component::<{}>()", component_type, component_type)))?;
|
||||
// this is just a placeholder value to protect against duplicates
|
||||
component_data = true;
|
||||
map.next_value_seed(ComponentDataDeserializer {
|
||||
entity: self.entity,
|
||||
world: self.world,
|
||||
component_registration,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct ComponentDataDeserializer<'a> {
|
||||
pub component_registration: &'a ComponentRegistration,
|
||||
pub world: &'a mut World,
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
impl<'a, 'de> DeserializeSeed<'de> for ComponentDataDeserializer<'a> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
if let Err(err) = (self.component_registration.individual_comp_deserialize_fn)(
|
||||
&mut erased_serde::Deserializer::erase(deserializer),
|
||||
self.world,
|
||||
self.entity,
|
||||
) {
|
||||
return Err(Error::custom(err.to_string()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,37 +1,10 @@
|
|||
use crate::ComponentRegistration;
|
||||
use crate::{ComponentRegistry, Scene, ComponentRegistration};
|
||||
use legion::{
|
||||
prelude::{Entity, World},
|
||||
storage::{ComponentMeta, ComponentStorage, ComponentTypeId, ComponentResourceSet},
|
||||
prelude::Entity,
|
||||
storage::{ComponentMeta, ComponentResourceSet, ComponentStorage, ComponentTypeId},
|
||||
};
|
||||
use serde::{
|
||||
ser::{Serialize, SerializeSeq, SerializeStruct},
|
||||
Deserialize,
|
||||
};
|
||||
use std::{cell::RefCell, collections::HashMap};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Scene {
|
||||
pub world: World,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ComponentRegistry {
|
||||
pub registrations: HashMap<ComponentTypeId, ComponentRegistration>,
|
||||
}
|
||||
|
||||
impl ComponentRegistry {
|
||||
pub fn register<T>(&mut self)
|
||||
where
|
||||
T: Send + Sync + 'static + Serialize + for<'de> Deserialize<'de>,
|
||||
{
|
||||
let registration = ComponentRegistration::of::<T>();
|
||||
self.registrations.insert(registration.ty, registration);
|
||||
}
|
||||
|
||||
pub fn get(&self, type_id: ComponentTypeId) -> Option<&ComponentRegistration> {
|
||||
self.registrations.get(&type_id)
|
||||
}
|
||||
}
|
||||
use serde::ser::{Serialize, SerializeSeq, SerializeStruct};
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub struct SerializableScene<'a> {
|
||||
pub scene: &'a Scene,
|
||||
|
@ -68,13 +41,6 @@ impl<'a> Serialize for SerializableScene<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
// for entity in self.scene.world.iter_entities() {
|
||||
// seq.serialize_element(&WorldEntity {
|
||||
// world: &self.scene.world,
|
||||
// component_registry: &self.component_registry,
|
||||
// entity,
|
||||
// })?;
|
||||
// }
|
||||
|
||||
seq.end()
|
||||
}
|
||||
|
@ -125,7 +91,7 @@ impl<'a> Serialize for EntityComponents<'a> {
|
|||
seq.serialize_element(&EntityComponent {
|
||||
index: self.index,
|
||||
component_resource_set: self.component_storage.components(*component_type).unwrap(),
|
||||
component_registration: self.component_registry.get(*component_type).unwrap(),
|
||||
component_registration: self.component_registry.get(component_type).unwrap(),
|
||||
})?;
|
||||
}
|
||||
seq.end()
|
||||
|
@ -139,6 +105,44 @@ struct EntityComponent<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Serialize for EntityComponent<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_struct("Component", 2)?;
|
||||
state.serialize_field(
|
||||
"type",
|
||||
&ComponentName(self.component_registration.short_name),
|
||||
)?;
|
||||
state.serialize_field(
|
||||
"data",
|
||||
&ComponentData {
|
||||
index: self.index,
|
||||
component_registration: self.component_registration,
|
||||
component_resource_set: self.component_resource_set,
|
||||
},
|
||||
)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
struct ComponentName(&'static str);
|
||||
|
||||
impl<'a> Serialize for ComponentName {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.0)
|
||||
}
|
||||
}
|
||||
struct ComponentData<'a> {
|
||||
index: usize,
|
||||
component_resource_set: &'a ComponentResourceSet,
|
||||
component_registration: &'a ComponentRegistration,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for ComponentData<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
|
@ -1,5 +1,6 @@
|
|||
// adapted from https://github.com/TomGillen/legion/blob/master/examples/serde.rs
|
||||
|
||||
use crate::ComponentRegistry;
|
||||
use legion::{
|
||||
entity::{EntityIndex, GuidEntityAllocator},
|
||||
prelude::*,
|
||||
|
@ -12,10 +13,7 @@ use serde::{
|
|||
de::{self, DeserializeSeed, IgnoredAny, Visitor},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
use std::{
|
||||
cell::RefCell, collections::HashMap, iter::FromIterator, marker::PhantomData, num::Wrapping,
|
||||
ptr::NonNull,
|
||||
};
|
||||
use std::{cell::RefCell, marker::PhantomData, num::Wrapping, ptr::NonNull};
|
||||
|
||||
struct ComponentDeserializer<'de, T: Deserialize<'de>> {
|
||||
ptr: *mut T,
|
||||
|
@ -36,9 +34,9 @@ impl<'de, T: Deserialize<'de> + 'static> DeserializeSeed<'de> for ComponentDeser
|
|||
}
|
||||
}
|
||||
|
||||
struct ComponentSeqDeserializer<'a, T> {
|
||||
get_next_storage_fn: &'a mut dyn FnMut() -> Option<(NonNull<u8>, usize)>,
|
||||
_marker: PhantomData<T>,
|
||||
pub(crate) struct ComponentSeqDeserializer<'a, T> {
|
||||
pub get_next_storage_fn: &'a mut dyn FnMut() -> Option<(NonNull<u8>, usize)>,
|
||||
pub _marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'de, 'a, T: for<'b> Deserialize<'b> + 'static> DeserializeSeed<'de>
|
||||
|
@ -97,76 +95,18 @@ impl<'de, 'a, T: for<'b> Deserialize<'b> + 'static> Visitor<'de>
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComponentRegistration {
|
||||
pub ty: ComponentTypeId,
|
||||
pub comp_serialize_fn: fn(&ComponentResourceSet, &mut dyn FnMut(&dyn erased_serde::Serialize)),
|
||||
pub individual_comp_serialize_fn:
|
||||
fn(&ComponentResourceSet, usize, &mut dyn FnMut(&dyn erased_serde::Serialize)),
|
||||
pub comp_deserialize_fn: fn(
|
||||
deserializer: &mut dyn erased_serde::Deserializer,
|
||||
get_next_storage_fn: &mut dyn FnMut() -> Option<(NonNull<u8>, usize)>,
|
||||
) -> Result<(), erased_serde::Error>,
|
||||
pub register_comp_fn: fn(&mut ArchetypeDescription),
|
||||
}
|
||||
|
||||
impl ComponentRegistration {
|
||||
pub fn of<T: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static>() -> Self {
|
||||
Self {
|
||||
ty: ComponentTypeId::of::<T>(),
|
||||
comp_serialize_fn: |comp_storage, serialize_fn| {
|
||||
// it's safe because we know this is the correct type due to lookup
|
||||
let slice = unsafe { comp_storage.data_slice::<T>() };
|
||||
serialize_fn(&*slice);
|
||||
},
|
||||
individual_comp_serialize_fn: |comp_storage, index: usize, serialize_fn| {
|
||||
// it's safe because we know this is the correct type due to lookup
|
||||
let slice = unsafe { comp_storage.data_slice::<T>() };
|
||||
serialize_fn(&slice[index]);
|
||||
},
|
||||
comp_deserialize_fn: |deserializer, get_next_storage_fn| {
|
||||
let comp_seq_deser = ComponentSeqDeserializer::<T> {
|
||||
get_next_storage_fn,
|
||||
_marker: PhantomData,
|
||||
};
|
||||
comp_seq_deser.deserialize(deserializer)?;
|
||||
Ok(())
|
||||
},
|
||||
register_comp_fn: |desc| {
|
||||
desc.register_component::<T>();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SerializedArchetypeDescription {
|
||||
tag_types: Vec<String>,
|
||||
component_types: Vec<String>,
|
||||
}
|
||||
|
||||
pub struct SerializeImpl {
|
||||
pub comp_types: HashMap<String, ComponentRegistration>,
|
||||
}
|
||||
|
||||
impl SerializeImpl {
|
||||
pub fn new(component_registrations: &[ComponentRegistration]) -> Self {
|
||||
SerializeImpl {
|
||||
comp_types: HashMap::from_iter(
|
||||
component_registrations
|
||||
.iter()
|
||||
.map(|reg| (reg.ty.0.to_string(), reg.clone())),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl legion::serialize::ser::WorldSerializer for SerializeImpl {
|
||||
impl legion::serialize::ser::WorldSerializer for ComponentRegistry {
|
||||
fn can_serialize_tag(&self, _ty: &TagTypeId, _meta: &TagMeta) -> bool {
|
||||
false
|
||||
}
|
||||
fn can_serialize_component(&self, ty: &ComponentTypeId, _meta: &ComponentMeta) -> bool {
|
||||
self.comp_types.get(ty.0).is_some()
|
||||
self.get(ty).is_some()
|
||||
}
|
||||
fn serialize_archetype_description<S: Serializer>(
|
||||
&self,
|
||||
|
@ -196,7 +136,7 @@ impl legion::serialize::ser::WorldSerializer for SerializeImpl {
|
|||
_component_meta: &ComponentMeta,
|
||||
components: &ComponentResourceSet,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
if let Some(reg) = self.comp_types.get(component_type.0) {
|
||||
if let Some(reg) = self.get(component_type) {
|
||||
let result = RefCell::new(None);
|
||||
let serializer = RefCell::new(Some(serializer));
|
||||
{
|
||||
|
@ -236,19 +176,7 @@ impl legion::serialize::ser::WorldSerializer for SerializeImpl {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct DeserializeImpl<'a> {
|
||||
pub comp_types: &'a HashMap<String, ComponentRegistration>,
|
||||
}
|
||||
|
||||
impl<'a> DeserializeImpl<'a> {
|
||||
pub fn new(component_types: &'a HashMap<String, ComponentRegistration>) -> Self {
|
||||
DeserializeImpl {
|
||||
comp_types: component_types,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> legion::serialize::de::WorldDeserializer for DeserializeImpl<'a> {
|
||||
impl<'a> legion::serialize::de::WorldDeserializer for ComponentRegistry {
|
||||
fn deserialize_archetype_description<'de, D: Deserializer<'de>>(
|
||||
&self,
|
||||
deserializer: D,
|
||||
|
@ -258,7 +186,7 @@ impl<'a> legion::serialize::de::WorldDeserializer for DeserializeImpl<'a> {
|
|||
let mut desc = ArchetypeDescription::default();
|
||||
|
||||
for comp in serialized_desc.component_types {
|
||||
if let Some(reg) = self.comp_types.get(&comp) {
|
||||
if let Some(reg) = self.get_with_full_name(&comp) {
|
||||
(reg.register_comp_fn)(&mut desc);
|
||||
}
|
||||
}
|
||||
|
@ -271,7 +199,7 @@ impl<'a> legion::serialize::de::WorldDeserializer for DeserializeImpl<'a> {
|
|||
_component_meta: &ComponentMeta,
|
||||
get_next_storage_fn: &mut dyn FnMut() -> Option<(NonNull<u8>, usize)>,
|
||||
) -> Result<(), <D as Deserializer<'de>>::Error> {
|
||||
if let Some(reg) = self.comp_types.get(component_type.0) {
|
||||
if let Some(reg) = self.get(component_type) {
|
||||
let mut erased = erased_serde::Deserializer::erase(deserializer);
|
||||
(reg.comp_deserialize_fn)(&mut erased, get_next_storage_fn)
|
||||
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)?;
|
|
@ -1,4 +0,0 @@
|
|||
mod world;
|
||||
mod scene;
|
||||
pub use world::*;
|
||||
pub use scene::*;
|
|
@ -3,7 +3,7 @@ use anyhow::Result;
|
|||
use bevy_asset::AssetLoader;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Default)]
|
||||
pub struct FontLoader;
|
||||
|
||||
impl AssetLoader<Font> for FontLoader {
|
||||
|
|
|
@ -13,6 +13,7 @@ pub struct TextPlugin;
|
|||
|
||||
impl AppPlugin for TextPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
app.add_asset::<Font>().add_asset_loader(FontLoader);
|
||||
app.add_asset::<Font>()
|
||||
.add_asset_loader::<Font, FontLoader>();
|
||||
}
|
||||
}
|
||||
|
|
34
examples/scene/load_scene.rs
Normal file
34
examples/scene/load_scene.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use bevy::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_default_plugins()
|
||||
// Registering components informs Bevy that they exist. This allows them to be used when loading/saving scenes
|
||||
.register_component::<Test>()
|
||||
.register_component::<Foo>()
|
||||
.add_startup_system(load_scene)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Test {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Foo {
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
fn load_scene(_world: &mut World, resources: &mut Resources) {
|
||||
let asset_server = resources.get::<AssetServer>().unwrap();
|
||||
let mut scenes = resources.get_mut::<Assets<Scene>>().unwrap();
|
||||
|
||||
let scene_handle: Handle<Scene> = asset_server
|
||||
.load_sync(&mut scenes, "assets/scene/load_scene_example.scn")
|
||||
.unwrap();
|
||||
let _scene= scenes.get(&scene_handle).unwrap();
|
||||
// world.merge(scene)
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
use bevy::{prelude::*, serialization::*};
|
||||
use legion::serialize::{de::deserialize, ser::serializable_world};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_plugin(ScheduleRunnerPlugin::run_once())
|
||||
// .add_startup_system(setup)
|
||||
.add_startup_system(setup_scene.system())
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Test {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Foo {
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
fn setup_scene() {
|
||||
let mut component_registry = ComponentRegistry::default();
|
||||
component_registry.register::<Test>();
|
||||
component_registry.register::<Foo>();
|
||||
|
||||
let mut scene = Scene::default();
|
||||
scene.world.insert((), vec![(Test { x: 3.0, y: 4.0 }, Foo { value: "hi".to_string()}),]);
|
||||
scene.world.insert((), vec![(Test { x: 3.0, y: 4.0 },)]);
|
||||
|
||||
let serializable_scene = SerializableScene::new(&scene, &component_registry);
|
||||
|
||||
let mut serializer = ron::ser::Serializer::new(Some(ron::ser::PrettyConfig::default()), true);
|
||||
serializable_scene.serialize(&mut serializer).unwrap();
|
||||
println!("{}", serializer.into_output_string());
|
||||
}
|
||||
|
||||
fn _setup(world: &mut World, resources: &mut Resources) {
|
||||
world.insert((), vec![(Test { x: 3.0, y: 4.0 },)]);
|
||||
|
||||
let comp_registrations = [ComponentRegistration::of::<Test>()];
|
||||
|
||||
let ser_helper = SerializeImpl::new(&comp_registrations);
|
||||
let serializable = serializable_world(world, &ser_helper);
|
||||
println!("JSON");
|
||||
let serialized_data = serde_json::to_string(&serializable).unwrap();
|
||||
println!("{}", serialized_data);
|
||||
println!();
|
||||
|
||||
println!("RON");
|
||||
let pretty = ron::ser::PrettyConfig {
|
||||
depth_limit: 2,
|
||||
separate_tuple_members: true,
|
||||
enumerate_arrays: true,
|
||||
..Default::default()
|
||||
};
|
||||
let s = ron::ser::to_string_pretty(&serializable, pretty.clone()).expect("Serialization failed");
|
||||
println!("{}", s);
|
||||
println!();
|
||||
|
||||
|
||||
let universe = resources.get_mut::<Universe>().unwrap();
|
||||
println!("JSON (Round Trip)");
|
||||
let de_helper = DeserializeImpl::new(&ser_helper.comp_types);
|
||||
let mut new_world = universe.create_world();
|
||||
let mut deserializer = serde_json::Deserializer::from_str(&serialized_data);
|
||||
deserialize(&mut new_world, &de_helper, &mut deserializer).unwrap();
|
||||
let round_trip_ser_helper =
|
||||
SerializeImpl::new(&comp_registrations);
|
||||
let serializable = serializable_world(&new_world, &round_trip_ser_helper);
|
||||
let roundtrip_data = serde_json::to_string(&serializable).unwrap();
|
||||
println!("{}", roundtrip_data);
|
||||
assert_eq!(roundtrip_data, serialized_data);
|
||||
|
||||
println!("RON (Round Trip)");
|
||||
let de_helper = DeserializeImpl::new(&ser_helper.comp_types);
|
||||
let mut new_world = universe.create_world();
|
||||
let mut deserializer = ron::de::Deserializer::from_str(&s).unwrap();
|
||||
deserialize(&mut new_world, &de_helper, &mut deserializer).unwrap();
|
||||
let round_trip_ser_helper =
|
||||
SerializeImpl::new(&comp_registrations);
|
||||
let serializable = serializable_world(&new_world, &round_trip_ser_helper);
|
||||
let roundtrip_data = ron::ser::to_string_pretty(&serializable, pretty).expect("Serialization failed");
|
||||
println!("{}", roundtrip_data);
|
||||
assert_eq!(roundtrip_data, s);
|
||||
}
|
|
@ -12,6 +12,9 @@ impl AddDefaultPlugins for AppBuilder {
|
|||
#[cfg(feature = "diagnostic")]
|
||||
self.add_plugin(bevy_diagnostic::DiagnosticsPlugin::default());
|
||||
|
||||
#[cfg(feature = "scene")]
|
||||
self.add_plugin(bevy_scene::ComponentRegistryPlugin::default());
|
||||
|
||||
#[cfg(feature = "input")]
|
||||
self.add_plugin(bevy_input::InputPlugin::default());
|
||||
|
||||
|
@ -21,6 +24,9 @@ impl AddDefaultPlugins for AppBuilder {
|
|||
#[cfg(feature = "asset")]
|
||||
self.add_plugin(bevy_asset::AssetPlugin::default());
|
||||
|
||||
#[cfg(feature = "scene")]
|
||||
self.add_plugin(bevy_scene::ScenePlugin::default());
|
||||
|
||||
#[cfg(feature = "render")]
|
||||
self.add_plugin(bevy_render::RenderPlugin::default());
|
||||
|
||||
|
|
|
@ -61,10 +61,12 @@ pub use bevy_gltf as gltf;
|
|||
pub use bevy_input as input;
|
||||
#[cfg(feature = "pbr")]
|
||||
pub use bevy_pbr as pbr;
|
||||
#[cfg(feature = "props")]
|
||||
pub use bevy_props as props;
|
||||
#[cfg(feature = "render")]
|
||||
pub use bevy_render as render;
|
||||
#[cfg(feature = "serialization")]
|
||||
pub use bevy_serialization as serialization;
|
||||
#[cfg(feature = "scene")]
|
||||
pub use bevy_scene as scene;
|
||||
#[cfg(feature = "text")]
|
||||
pub use bevy_text as text;
|
||||
#[cfg(feature = "transform")]
|
||||
|
|
|
@ -29,6 +29,8 @@ pub use crate::render::{
|
|||
texture::{Texture, TextureType},
|
||||
ActiveCamera, ActiveCamera2d, Camera, CameraType, Color, ColorSource, Renderable,
|
||||
};
|
||||
#[cfg(feature = "scene")]
|
||||
pub use crate::scene::{Scene, RegisterComponent};
|
||||
#[cfg(feature = "text")]
|
||||
pub use crate::text::Font;
|
||||
#[cfg(feature = "transform")]
|
||||
|
|
Loading…
Reference in a new issue