Skip to content

DynamicScenes contain invalid Entity references #4793

@Azorlogh

Description

@Azorlogh

Bevy version

Commit hash: 15acd6f (post v0.7.0)

Bug description

Minimal example

Details
use bevy::{ecs::entity::EntityMap, prelude::*};

fn main() {
  App::new()
    .add_plugins(DefaultPlugins)
    .add_startup_system(save_scene_system)
    .run();
}

#[derive(Resource)]
pub struct StoredScene(Option<DynamicScene>);

fn save_scene_system(world: &mut World) {
  let mut scene_world = World::new();

  // Uncomment the following lines to cause the bug!
  let child = scene_world.spawn(()).id();
  scene_world.despawn(child);

  let child = scene_world.spawn(()).id();

  scene_world.spawn(()).push_children(&[child]);

  let type_registry = world.resource::<AppTypeRegistry>();
  let scene = DynamicScene::from_world(&scene_world, type_registry);

  println!("{}", scene.serialize_ron(type_registry).unwrap());

  scene
    .write_to_world(world, &mut EntityMap::default())
    .unwrap();
}

When applying DynamicScenes to a world using write_to_world, the operation will sometimes panic.
(more specifically, it will crash if the DynamicScene was created from any entities with a generation != 0 which belong to a hierarchy)

Cause

DynamicScenes store entities without their generation, which makes sense because the simple ids are transiently unique.

However, Entitys stored in components (such as Parent or Children) still contain the generation.

This means that upon applying the DynamicScene, the mapping phase of write_to_world will try to map the "generationful" Entitys and will fail to find them in the map (because the map only has a 0-generation for its keys).

Important note

OUTDATED
I believe most people never encounter this problem, because DynamicScenes are mainly used alongside serialization, and serialization of an Entity strips it of its generation already. (I didn't find where in the codebase but it's what I deduce)

UPDATE:
The workaround above no longer works as per #6194

Proposed fix

OUTDATED
I believe we would simply need to add a prior mapping phase in DynamicScene::from_world to strip the generation of all Entitys contained in components.
I will file a PR soon. Nevermind, I am not well-enough versed in the deep arts of reflection

UPDATE:
Since the arguments in #6194 are convincing that serializing the generation is useful, I think we need another solution.
Possibly, storing the generation in the DynamicScenes

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ScenesComposing and serializing ECS objectsC-BugAn unexpected or incorrect behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions