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

Create a DynamicScene from a world and an entity root #6013

Closed
wants to merge 7 commits into from

Conversation

mockersf
Copy link
Member

@mockersf mockersf commented Sep 18, 2022

Objective

  • Create a dynamic scene from a world and an entity root.
  • Sneaked in a few improvements on Scene and DynamicScene to have a more coherent API between the two

Solution

  • From the root, select all entities that are in the world and descendent of root, and extract all registered components to a dynamic scene

extract all registered components:

DynamicScene::from_world_at_root(
    world,
    Entity::from_bits(0), // Should be a proper way to have an entity here
    world.resource::<AppTypeRegistry>(),
);

extract only a subset of components (here Transform):

let mut atr = AppTypeRegistry::default();
atr.write().register::<Transform>();
DynamicScene::from_world_at_root(
    world,
    Entity::from_bits(0), // Should be a proper way to have an entity here
    &atr,
);

@mockersf mockersf added the A-Scenes Serialized ECS data stored on the disk label Sep 18, 2022
@alice-i-cecile alice-i-cecile added the C-Feature A new feature, making something new possible label Sep 18, 2022

/// To spawn a scene, you can use either:
/// * [`SceneSpawner::spawn`](crate::SceneSpawner::spawn)
/// * adding the [`SceneBundle`](crate::SceneBundle) to an entity
/// * adding the [`Handle<Scene>`](bevy_asset::Handle) to an entity (the scene will only be
/// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and
/// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components)
#[derive(Debug, TypeUuid)]
#[derive(Debug, TypeUuid, Deref, DerefMut)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm reluctant to add these derives; they make things more implicit and are likely to break once we need to add more fields.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the Deref / DerefMut impls on Scene should be their own PR so they get appropriate review attention.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'm reluctant to add these derives; they make things more implicit and are likely to break once we need to add more fields.

Then let's remove them later if we need to add more fields? For now they make working with scenes a lot nicer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disagreed. Why introduce extra implicitness and potential for future breaking changes, just to save on typing a .0. I wouldn't call this "a lot nicer".

Copy link
Member Author

@mockersf mockersf Sep 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well then we're back to arguing against the Deref derive that we promotes in Bevy: https://bevyengine.org/news/bevy-0-7/#deref-derefmut-derives

I'm not sure there are plans to add more fields to Scene at the moment?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm fine to leave it. We should write a manual Deref / DerefMut impl if and when we add more fields then, and call this out in the docs though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I don't think the Deref/DerefMut derives are needed. It's probably better for users to explicitly be aware that what they're working with is basically just a plain ol' World. And yeah, it makes future additions to Scenes less problematic (e.g. versioning, etc.).

/// Create a new dynamic scene from a given [`World`] at a given [`Entity`].
///
/// All descendants entities from the given one will be extracted.
pub fn from_world_at_root(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bikeshed: i think the "at root" naming is confusing. I'd probably have called this from_world_entity_recursive.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

totally open to changing the name, even more if we change it to take several entities as input

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO from_entity_recursive or from_entities_and_children or something. I think the from_world bit is unhelpful in context and can just be dropped.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually cast my vote for a simple from_root. Imo it's implicit that we're talking about worlds and entities here. If we want to be a little more specific, I think from_entity is fine too— although, it could be slightly confusing as to whether this recurses into children or not.

Next best would probably be from_entity_recursive.


/// To spawn a scene, you can use either:
/// * [`SceneSpawner::spawn`](crate::SceneSpawner::spawn)
/// * adding the [`SceneBundle`](crate::SceneBundle) to an entity
/// * adding the [`Handle<Scene>`](bevy_asset::Handle) to an entity (the scene will only be
/// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and
/// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components)
#[derive(Debug, TypeUuid)]
#[derive(Debug, TypeUuid, Deref, DerefMut)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disagreed. Why introduce extra implicitness and potential for future breaking changes, just to save on typing a .0. I wouldn't call this "a lot nicer".

crates/bevy_scene/src/scene_spawner.rs Show resolved Hide resolved
/// All descendants entities from the given one will be extracted.
pub fn from_world_at_root(
world: &World,
root: Entity,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I think this method would have limited practical utility. Who wants to create a scene from just one entity (+ children)? Sure, sometimes you might have such a use case, but it seems needlessly limited. What if you want a second entity? Or a few more?

Why not change this to impl IntoIterator<Item=Entity>, allowing users to provide any number of root entities?

Would add a little extra complexity to the body of the function. Perhaps there should be some sort of deduplication logic to prevent redundant/duplicate entities in the scene. One suggestion might be to use an intermediary HashSet instead of a Vec. Or maybe we could just not do any deduplication (just accumulate all the entities into the scene without regard for duplicates), and document it as a caveat / leave it to the users to make sure they don't have duplicate entities in their list of roots.

It would make this function much more practical and useful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you prefer to be able to append to an existing scene? Or just creating from multiple entities

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well now that you have said it ... i guess both? 😆

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine single-entity scenes could be super useful for prefab-like serialization and usage.

But I agree it could also be useful to handle multiple at a time. Perhaps a method for a single root and another for multiple?

Copy link
Member

@MrGVSV MrGVSV left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments. One thing I think we should add, though, is a new example that showcases both creating a scene from a root entity and also filtering by component (the latter could maybe go in the existing scene.rs example if it's not too crowded).

@@ -20,6 +20,22 @@ pub struct DespawnChildrenRecursive {
pub entity: Entity,
}

/// List all descendants of a given entity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you expand on this? Specifically, is the returned Vec<Entity> a depth-first traversal down the hierarchy or breadth-first?

@@ -76,17 +78,60 @@ impl DynamicScene {
scene
}

/// Create a new dynamic scene from a given [`World`] at a given [`Entity`].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

Suggested change
/// Create a new dynamic scene from a given [`World`] at a given [`Entity`].
/// Create a new dynamic scene from a given [`World`] at a given [`Entity`] root.

/// Create a new dynamic scene from a given [`World`] at a given [`Entity`].
///
/// All descendants entities from the given one will be extracted.
pub fn from_world_at_root(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually cast my vote for a simple from_root. Imo it's implicit that we're talking about worlds and entities here. If we want to be a little more specific, I think from_entity is fine too— although, it could be slightly confusing as to whether this recurses into children or not.

Next best would probably be from_entity_recursive.

/// All descendants entities from the given one will be extracted.
pub fn from_world_at_root(
world: &World,
root: Entity,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine single-entity scenes could be super useful for prefab-like serialization and usage.

But I agree it could also be useful to handle multiple at a time. Perhaps a method for a single root and another for multiple?

Comment on lines +93 to +94
let mut entities_of_interest = list_all_descendants(world, root);
entities_of_interest.push(root);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This is more of a stylistic thing I suppose, but should the root come first in this list?

Suggested change
let mut entities_of_interest = list_all_descendants(world, root);
entities_of_interest.push(root);
let mut entities_of_interest =
std::iter::once(root).chain(list_all_descendants(world, root));

/// Write the dynamic entities and their corresponding components to the given world.
///
/// This method will return a [`SceneSpawnError`] if a type either is not registered
/// or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait.
pub fn write_to_world(
pub fn write_to_world_with(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be a separate method so users that want to extract everything can don't need to add the extra world.resource::<AppTypeRegistry>() call.

Comment on lines 124 to 127
/// Write the dynamic entities and their corresponding components to the given world.
///
/// This method will return a [`SceneSpawnError`] if a type either is not registered
/// or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation should include information about the registry filter.


/// To spawn a scene, you can use either:
/// * [`SceneSpawner::spawn`](crate::SceneSpawner::spawn)
/// * adding the [`SceneBundle`](crate::SceneBundle) to an entity
/// * adding the [`Handle<Scene>`](bevy_asset::Handle) to an entity (the scene will only be
/// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and
/// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components)
#[derive(Debug, TypeUuid)]
#[derive(Debug, TypeUuid, Deref, DerefMut)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I don't think the Deref/DerefMut derives are needed. It's probably better for users to explicitly be aware that what they're working with is basically just a plain ol' World. And yeah, it makes future additions to Scenes less problematic (e.g. versioning, etc.).

@alice-i-cecile
Copy link
Member

Closed in favor of #6227.

bors bot pushed a commit that referenced this pull request Oct 12, 2022
# Objective

- make it easier to build dynamic scenes

## Solution

- add a builder to create a dynamic scene from a world. it can extract an entity or an iterator of entities
- alternative to #6013, leaving the "hierarchy iteration" part to #6185 which does it better
- alternative to #6004 
- using a builder makes it easier to chain several extractions
james7132 pushed a commit to james7132/bevy that referenced this pull request Oct 19, 2022
# Objective

- make it easier to build dynamic scenes

## Solution

- add a builder to create a dynamic scene from a world. it can extract an entity or an iterator of entities
- alternative to bevyengine#6013, leaving the "hierarchy iteration" part to bevyengine#6185 which does it better
- alternative to bevyengine#6004 
- using a builder makes it easier to chain several extractions
james7132 pushed a commit to james7132/bevy that referenced this pull request Oct 28, 2022
# Objective

- make it easier to build dynamic scenes

## Solution

- add a builder to create a dynamic scene from a world. it can extract an entity or an iterator of entities
- alternative to bevyengine#6013, leaving the "hierarchy iteration" part to bevyengine#6185 which does it better
- alternative to bevyengine#6004 
- using a builder makes it easier to chain several extractions
Pietrek14 pushed a commit to Pietrek14/bevy that referenced this pull request Dec 17, 2022
# Objective

- make it easier to build dynamic scenes

## Solution

- add a builder to create a dynamic scene from a world. it can extract an entity or an iterator of entities
- alternative to bevyengine#6013, leaving the "hierarchy iteration" part to bevyengine#6185 which does it better
- alternative to bevyengine#6004 
- using a builder makes it easier to chain several extractions
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
# Objective

- make it easier to build dynamic scenes

## Solution

- add a builder to create a dynamic scene from a world. it can extract an entity or an iterator of entities
- alternative to bevyengine#6013, leaving the "hierarchy iteration" part to bevyengine#6185 which does it better
- alternative to bevyengine#6004 
- using a builder makes it easier to chain several extractions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Scenes Serialized ECS data stored on the disk C-Feature A new feature, making something new possible
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants