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

Cannot Deserialize Camera2dBundle because of the OrthographicProjection component #10284

Closed
asdfsdfsdfzhjzu opened this issue Oct 27, 2023 · 2 comments · Fixed by #15174
Closed
Labels
A-Reflection Runtime information about types A-Scenes Serialized ECS data stored on the disk C-Bug An unexpected or incorrect behavior

Comments

@asdfsdfsdfzhjzu
Copy link

Bevy version

0.11.3

[Optional] Relevant system information

AdapterInfo { name: "AMD JUNIPER (DRM 2.50.0 / 6.5.6-arch2-1, LLVM 16.0.6)", vendor: 65541, device: 0, device_type: Other, driver: "", driver_info: "", backend: Gl }

What you did

i saved and loaded a camerabundle2d :


use bevy::prelude::*;
use std::fs::File;
use bevy::tasks::IoTaskPool;
use std::io::Write;

fn main() {
    App::new()
    .add_plugins(DefaultPlugins)

    .add_systems(Startup, setup_save) // run once to generate save then comment and uncomment the line below to load
    //.add_systems(Startup, setup_load)
    .add_systems(Update, save)
    .add_systems(Update, load)
    .run();
}

#[derive(Component,Reflect,Default)]
pub struct Load;
#[derive(Component,Reflect)]
pub struct Save(Entity);

fn setup_save(
    mut commands : Commands
){
    let ent = commands.spawn(Camera2dBundle::default()).id();
    commands.spawn(Save(ent));
    println!("setup");
}

fn setup_load(
    mut commands : Commands
){
    commands.spawn(Load);
    println!("setup load");
}

fn save(
    world: &World,
    query : Query<(&Save)>,

    mut commands : Commands
) {
    for s in query.iter(){
        let savegame_save_path : &str = "assets/savegame.scn.ron";

        let mut entity_array = vec![s.0];

        let mut scene_builder =  DynamicSceneBuilder::from_world(world);
        scene_builder.allow_all();

        scene_builder.deny::<ComputedVisibility>();// cant currently serialize with ComputedVisibilityFlags

        scene_builder.extract_entities(entity_array.into_iter());
        let scene = scene_builder.build();

        let type_registry = world.resource::<AppTypeRegistry>().clone();
        let serialized_scene = scene.serialize_ron(&type_registry).unwrap();

        
        #[cfg(not(target_arch = "wasm32"))]
        IoTaskPool::get()
            .spawn(async move {

                File::create(savegame_save_path)
                    .and_then(|mut file| file.write(serialized_scene.as_bytes()))
                    .expect("Error while writing scene to file");
            })
            .detach();
            println!("save");
        commands.entity(s.0).despawn_recursive();
    }
}

fn load(
    loaded_query : Query<&Load>,
    mut commands : Commands,
    asset_server: Res<AssetServer>,
) {
    for i in loaded_query.iter(){
        println!("load");
        let save_path : &str = "savegame.scn.ron";

        let scenehandle = asset_server.load(save_path);
        commands.spawn(DynamicSceneBundle {

            scene: scenehandle,
            ..default()
        });
    }
}

What went wrong

it wont load instead it will print an error like this:
WARN bevy_asset::asset_server: encountered an error while loading an asset: Expected float at savegame.scn.ron:25:15
which points to : x: -640.0,

@asdfsdfsdfzhjzu asdfsdfsdfzhjzu added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Oct 27, 2023
@asdfsdfsdfzhjzu
Copy link
Author

asdfsdfsdfzhjzu commented Oct 27, 2023

it seems that the OrthographicProjection component inside the camer2dbundle is causing the error you can just spawn OrthographicProjection instead of the camerbundle and get the same error.
i tested all the other components inside the camer2dbundle and they all can be loaded

@asdfsdfsdfzhjzu asdfsdfsdfzhjzu changed the title Cannot Deserialize Camera2dBundle Cannot Deserialize Camera2dBundle because of the OrthographicProjection component Oct 27, 2023
@rparrett
Copy link
Contributor

rparrett commented Oct 27, 2023

Related issue: #9060. But it seems like this might be a separate thing.

I am seeing the same Expected float error with bevy main after migrating your example.

@rparrett rparrett added A-Reflection Runtime information about types A-Scenes Serialized ECS data stored on the disk and removed S-Needs-Triage This issue needs to be labelled labels Oct 27, 2023
yrns added a commit to yrns/bevy that referenced this issue Sep 11, 2024
github-merge-queue bot pushed a commit that referenced this issue Sep 15, 2024
# 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
(#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::camera::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::camera::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 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Reflection Runtime information about types A-Scenes Serialized ECS data stored on the disk C-Bug An unexpected or incorrect behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants