bevy/crates
Al M. 2ea51fc60f
Use FromReflect when extracting entities in dynamic scenes (#15174)
# Objective

Fix #10284.

## Solution

When `DynamicSceneBuilder` extracts entities, they are cloned via
`PartialReflect::clone_value`, making them into dynamic versions of the
original components. This loses any custom `ReflectSerialize` type data.
Dynamic scenes are deserialized with the original types, not the dynamic
versions, and so any component with a custom serialize may fail. In this
case `Rect` and `Vec2`. The dynamic version includes the field names 'x'
and 'y' but the `Serialize` impl doesn't, hence the "expect float"
error.

The solution here: Instead of using `clone_value` to clone the
components, `FromReflect` clones and retains the original information
needed to serialize with any custom `Serialize` impls. I think using
something like `reflect_clone` from
(https://github.com/bevyengine/bevy/pull/13432) might make this more
efficient.

I also did the same when deserializing dynamic scenes to appease some of
the round-trip tests which use `ReflectPartialEq`, which requires the
types be the same and not a unique/proxy pair. I'm not sure it's
otherwise necessary. Maybe this would also be more efficient when
spawning dynamic scenes with `reflect_clone` instead of `FromReflect`
again?

An alternative solution would be to fall back to the dynamic version
when deserializing `DynamicScene`s if the custom version fails. I think
that's possible. Or maybe simply always deserializing via the dynamic
route for dynamic scenes?

## Testing

This example is similar to the original test case in #10284:

``` rust
#![allow(missing_docs)]

use bevy::{prelude::*, scene::SceneInstanceReady};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, (save, load).chain())
        .observe(check)
        .run();
}

static SAVEGAME_SAVE_PATH: &str = "savegame.scn.ron";

fn save(world: &mut World) {
    let entity = world.spawn(OrthographicProjection::default()).id();

    let scene = DynamicSceneBuilder::from_world(world)
        .extract_entity(entity)
        .build();

    if let Some(registry) = world.get_resource::<AppTypeRegistry>() {
        let registry = registry.read();
        let serialized_scene = scene.serialize(&registry).unwrap();
        // println!("{}", serialized_scene);
        std::fs::write(format!("assets/{SAVEGAME_SAVE_PATH}"), serialized_scene).unwrap();
    }

    world.entity_mut(entity).despawn_recursive();
}

fn load(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn(DynamicSceneBundle {
        scene: asset_server.load(SAVEGAME_SAVE_PATH),
        ..default()
    });
}

fn check(_trigger: Trigger<SceneInstanceReady>, query: Query<&OrthographicProjection>) {
    dbg!(query.single());
}
```


## Migration Guide

The `DynamicScene` format is changed to use custom serialize impls so
old scene files will need updating:

Old: 

```ron
(
  resources: {},
  entities: {
    4294967299: (
      components: {
        "bevy_render:📷:projection::OrthographicProjection": (
          near: 0.0,
          far: 1000.0,
          viewport_origin: (
            x: 0.5,
            y: 0.5,
          ),
          scaling_mode: WindowSize(1.0),
          scale: 1.0,
          area: (
            min: (
              x: -1.0,
              y: -1.0,
            ),
            max: (
              x: 1.0,
              y: 1.0,
            ),
          ),
        ),
      },
    ),
  },
)
```

New:

```ron
(
  resources: {},
  entities: {
    4294967299: (
      components: {
        "bevy_render:📷:projection::OrthographicProjection": (
          near: 0.0,
          far: 1000.0,
          viewport_origin: (0.5, 0.5),
          scaling_mode: WindowSize(1.0),
          scale: 1.0,
          area: (
            min: (-1.0, -1.0),
            max: (1.0, 1.0),
          ),
        ),
      },
    ),
  },
)
```

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-09-15 14:33:39 +00:00
..
bevy_a11y Reflected traits for resources and components: bevy_a11y (#15192) 2024-09-14 01:43:16 +00:00
bevy_animation Reflect derived traits on all components and resources: bevy_animation (#15209) 2024-09-15 11:58:51 +00:00
bevy_app Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_asset Reccomend using AssetPlugin.file_path instead of CARGO_MANIFEST_DIR (#15176) 2024-09-13 16:16:23 +00:00
bevy_audio Reflect derived traits on all components and resources: bevy_audio (#15211) 2024-09-15 14:24:00 +00:00
bevy_color Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_core Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_core_pipeline Reflect derived traits on all components and resources: bevy_core_pipeline (#15213) 2024-09-15 14:23:41 +00:00
bevy_derive Remove deprecated bevy_dynamic_plugin (#14534) 2024-07-30 15:31:08 +00:00
bevy_dev_tools Split OrthographicProjection::default into 2d & 3d (Adopted) (#15073) 2024-09-09 15:51:28 +00:00
bevy_diagnostic Apply unused_qualifications lint (#14828) 2024-08-21 12:29:33 +00:00
bevy_dylib Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965) 2024-07-29 23:10:16 +00:00
bevy_ecs Example for bevy_ecs::event::Events uses deprecated function get_reader (#15216) 2024-09-15 14:24:04 +00:00
bevy_encase_derive Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965) 2024-07-29 23:10:16 +00:00
bevy_gilrs Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965) 2024-07-29 23:10:16 +00:00
bevy_gizmos Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_gltf Remove OrthographicProjection.scale (adopted) (#15075) 2024-09-09 22:34:58 +00:00
bevy_hierarchy Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_input Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_internal Remove all existing system order ambiguities in DefaultPlugins (#15031) 2024-09-03 20:24:34 +00:00
bevy_log Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_macro_utils Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965) 2024-07-29 23:10:16 +00:00
bevy_math Fix Capsule2d::sample_interior (#15191) 2024-09-14 02:24:08 +00:00
bevy_mikktspace Fix underflow panic in InitTriInfo (#14893) 2024-08-25 14:13:23 +00:00
bevy_pbr Rename rendering components for improved consistency and clarity (#15035) 2024-09-10 01:11:46 +00:00
bevy_picking Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_ptr Migrated NonZero* to NonZero<*> (#14978) 2024-08-30 02:37:47 +00:00
bevy_reflect Use FromReflect when extracting entities in dynamic scenes (#15174) 2024-09-15 14:33:39 +00:00
bevy_render TrackedRenderPass internal tracking state reset (#14948) 2024-09-12 16:51:36 +00:00
bevy_scene Use FromReflect when extracting entities in dynamic scenes (#15174) 2024-09-15 14:33:39 +00:00
bevy_sprite Fix mesh 2d non indexed draw. (#15155) 2024-09-12 12:38:56 +00:00
bevy_state Add state scoped events (#15085) 2024-09-09 16:37:27 +00:00
bevy_tasks Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_text Trim cosmic-text's shape run cache (#15037) 2024-09-10 23:28:05 +00:00
bevy_time Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_transform Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_ui Remove border radius scaling (#15173) 2024-09-13 15:52:42 +00:00
bevy_utils Remove remnant EntityHash and related types from bevy_utils (#15039) 2024-09-09 15:24:17 +00:00
bevy_window Remove ReceivedCharacter (#15126) 2024-09-10 00:22:06 +00:00
bevy_winit Remove ReceivedCharacter (#15126) 2024-09-10 00:22:06 +00:00