Skip to content

Commit

Permalink
Change SceneSpawner::spawn_dynamic_sync to return InstanceID (#11239)
Browse files Browse the repository at this point in the history
# Objective

`SceneSpawner::spawn_dynamic_sync` currently returns `()` on success,
which is inconsistent with the other `SceneSpawner::spawn_` methods that
all return an `InstanceId`. We need this ID to do useful work with the
newly-created data.

## Solution

Updated `SceneSpawner::spawn_dynamic_sync` to return `Result<InstanceId,
SceneSpawnError>` instead of `Result<(), SceneSpawnError>`
  • Loading branch information
thebluefish authored Jan 6, 2024
1 parent 0349809 commit cfcb688
Showing 1 changed file with 66 additions and 2 deletions.
68 changes: 66 additions & 2 deletions crates/bevy_scene/src/scene_spawner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ impl SceneSpawner {
&mut self,
world: &mut World,
id: impl Into<AssetId<DynamicScene>>,
) -> Result<(), SceneSpawnError> {
) -> Result<InstanceId, SceneSpawnError> {
let mut entity_map = EntityHashMap::default();
let id = id.into();
Self::spawn_dynamic_internal(world, id, &mut entity_map)?;
Expand All @@ -207,7 +207,7 @@ impl SceneSpawner {
.insert(instance_id, InstanceInfo { entity_map });
let spawned = self.spawned_dynamic_scenes.entry(id).or_default();
spawned.push(instance_id);
Ok(())
Ok(instance_id)
}

fn spawn_dynamic_internal(
Expand Down Expand Up @@ -434,3 +434,67 @@ pub fn scene_spawner_system(world: &mut World) {
scene_spawner.set_scene_instance_parent_sync(world);
});
}

#[cfg(test)]
mod tests {
use super::*;
use bevy_ecs::component::Component;
use bevy_ecs::entity::Entity;
use bevy_ecs::prelude::ReflectComponent;
use bevy_ecs::query::With;
use bevy_ecs::{reflect::AppTypeRegistry, world::World};

use crate::DynamicSceneBuilder;
use bevy_reflect::Reflect;

#[derive(Reflect, Component, Debug, PartialEq, Eq, Clone, Copy, Default)]
#[reflect(Component)]
struct A(usize);

#[test]
fn clone_dynamic_entities() {
let mut world = World::default();

// setup
let atr = AppTypeRegistry::default();
atr.write().register::<A>();
world.insert_resource(atr);
world.insert_resource(Assets::<DynamicScene>::default());

// start test
world.spawn(A(42));

assert_eq!(world.query::<&A>().iter(&world).len(), 1);

// clone only existing entity
let mut scene_spawner = SceneSpawner::default();
let entity = world.query_filtered::<Entity, With<A>>().single(&world);
let scene = DynamicSceneBuilder::from_world(&world)
.extract_entity(entity)
.build();

let scene_id = world.resource_mut::<Assets<DynamicScene>>().add(scene);
let instance_id = scene_spawner
.spawn_dynamic_sync(&mut world, scene_id)
.unwrap();

// verify we spawned exactly one new entity with our expected component
assert_eq!(world.query::<&A>().iter(&world).len(), 2);

// verify that we can get this newly-spawned entity by the instance ID
let new_entity = scene_spawner
.iter_instance_entities(instance_id)
.next()
.unwrap();

// verify this is not the original entity
assert_ne!(entity, new_entity);

// verify this new entity contains the same data as the original entity
let [old_a, new_a] = world
.query::<&A>()
.get_many(&world, [entity, new_entity])
.unwrap();
assert_eq!(old_a, new_a);
}
}

0 comments on commit cfcb688

Please sign in to comment.