Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can spawn a scene from a ChildBuilder, or directly set its parent when spawning it #1026

Merged
merged 2 commits into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/bevy_scene/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ bevy_app = { path = "../bevy_app", version = "0.3.0" }
bevy_asset = { path = "../bevy_asset", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_transform = { path = "../bevy_transform", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }

# other
Expand Down
29 changes: 28 additions & 1 deletion crates/bevy_scene/src/command.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use bevy_asset::Handle;
use bevy_ecs::{Command, Commands, Resources, World};
use bevy_ecs::{Command, Commands, Entity, Resources, World};
use bevy_transform::hierarchy::ChildBuilder;

use crate::{Scene, SceneSpawner};

Expand All @@ -23,3 +24,29 @@ impl SpawnSceneCommands for Commands {
self.add_command(SpawnScene { scene_handle })
}
}

pub struct SpawnSceneAsChild {
scene_handle: Handle<Scene>,
parent: Entity,
}

impl Command for SpawnSceneAsChild {
fn write(self: Box<Self>, _world: &mut World, resources: &mut Resources) {
let mut spawner = resources.get_mut::<SceneSpawner>().unwrap();
spawner.spawn_as_child(self.scene_handle, self.parent);
}
}

pub trait SpawnSceneAsChildCommands {
fn spawn_scene(&mut self, scene: Handle<Scene>) -> &mut Self;
}

impl<'a> SpawnSceneAsChildCommands for ChildBuilder<'a> {
fn spawn_scene(&mut self, scene_handle: Handle<Scene>) -> &mut Self {
self.add_command(SpawnSceneAsChild {
scene_handle,
parent: self.parent_entity(),
});
self
}
}
4 changes: 3 additions & 1 deletion crates/bevy_scene/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ pub use scene_loader::*;
pub use scene_spawner::*;

pub mod prelude {
pub use crate::{DynamicScene, Scene, SceneSpawner, SpawnSceneCommands};
pub use crate::{
DynamicScene, Scene, SceneSpawner, SpawnSceneAsChildCommands, SpawnSceneCommands,
};
}

use bevy_app::prelude::*;
Expand Down
51 changes: 44 additions & 7 deletions crates/bevy_scene/src/scene_spawner.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::{DynamicScene, Scene};
use bevy_app::prelude::*;
use bevy_asset::{AssetEvent, Assets, Handle};
use bevy_ecs::{EntityMap, Resources, World};
use bevy_ecs::{Entity, EntityMap, Resources, World};
use bevy_reflect::{ReflectComponent, ReflectMapEntities, TypeRegistryArc};
use bevy_transform::prelude::Parent;
use bevy_utils::HashMap;
use thiserror::Error;
use uuid::Uuid;
Expand All @@ -28,8 +29,9 @@ pub struct SceneSpawner {
spawned_instances: HashMap<InstanceId, InstanceInfo>,
scene_asset_event_reader: EventReader<AssetEvent<DynamicScene>>,
dynamic_scenes_to_spawn: Vec<Handle<DynamicScene>>,
scenes_to_spawn: Vec<Handle<Scene>>,
scenes_to_spawn: Vec<(Handle<Scene>, InstanceId)>,
scenes_to_despawn: Vec<Handle<DynamicScene>>,
scenes_with_parent: Vec<(InstanceId, Entity)>,
}

#[derive(Error, Debug)]
Expand All @@ -50,7 +52,14 @@ impl SceneSpawner {
}

pub fn spawn(&mut self, scene_handle: Handle<Scene>) {
self.scenes_to_spawn.push(scene_handle);
let instance_id = InstanceId::new();
self.scenes_to_spawn.push((scene_handle, instance_id));
}

pub fn spawn_as_child(&mut self, scene_handle: Handle<Scene>, parent: Entity) {
let instance_id = InstanceId::new();
self.scenes_to_spawn.push((scene_handle, instance_id));
self.scenes_with_parent.push((instance_id, parent));
}

pub fn despawn(&mut self, scene_handle: Handle<DynamicScene>) {
Expand Down Expand Up @@ -147,7 +156,16 @@ impl SceneSpawner {
resources: &Resources,
scene_handle: Handle<Scene>,
) -> Result<(), SceneSpawnError> {
let instance_id = InstanceId::new();
self.spawn_sync_internal(world, resources, scene_handle, InstanceId::new())
}

fn spawn_sync_internal(
&mut self,
world: &mut World,
resources: &Resources,
scene_handle: Handle<Scene>,
instance_id: InstanceId,
) -> Result<(), SceneSpawnError> {
let mut instance_info = InstanceInfo {
entity_map: EntityMap::default(),
};
Expand Down Expand Up @@ -256,18 +274,36 @@ impl SceneSpawner {

let scenes_to_spawn = std::mem::take(&mut self.scenes_to_spawn);

for scene_handle in scenes_to_spawn {
match self.spawn_sync(world, resources, scene_handle) {
for (scene_handle, instance_id) in scenes_to_spawn {
match self.spawn_sync_internal(world, resources, scene_handle, instance_id) {
Ok(_) => {}
Err(SceneSpawnError::NonExistentRealScene { handle }) => {
self.scenes_to_spawn.push(handle)
self.scenes_to_spawn.push((handle, instance_id))
}
Err(err) => return Err(err),
}
}

Ok(())
}

pub(crate) fn set_scene_instance_parent_sync(&mut self, world: &mut World) {
let scenes_with_parent = std::mem::take(&mut self.scenes_with_parent);

for (instance_id, parent) in scenes_with_parent {
if let Some(instance) = self.spawned_instances.get(&instance_id) {
for entity in instance.entity_map.values() {
if let Err(bevy_ecs::ComponentError::MissingComponent(_)) =
world.get::<Parent>(entity)
{
let _ = world.insert_one(entity, Parent(parent));
}
}
} else {
self.scenes_with_parent.push((instance_id, parent));
}
}
}
}

pub fn scene_spawner_system(world: &mut World, resources: &mut Resources) {
Expand All @@ -293,4 +329,5 @@ pub fn scene_spawner_system(world: &mut World, resources: &mut Resources) {
scene_spawner
.update_spawned_scenes(world, resources, &updated_spawned_scenes)
.unwrap();
scene_spawner.set_scene_instance_parent_sync(world);
}
9 changes: 9 additions & 0 deletions crates/bevy_transform/src/hierarchy/child_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ impl<'a> ChildBuilder<'a> {
self.commands.current_entity()
}

pub fn parent_entity(&self) -> Entity {
self.push_children.parent
}

pub fn with_bundle(
&mut self,
components: impl DynamicBundle + Send + Sync + 'static,
Expand All @@ -102,6 +106,11 @@ impl<'a> ChildBuilder<'a> {
func(current_entity);
self
}

pub fn add_command<C: Command + 'static>(&mut self, command: C) -> &mut Self {
self.commands.add_command(command);
self
}
}

pub trait BuildChildren {
Expand Down