When using DynamicScene to restore the state, StateScoped will not take effect
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
## Bevy version
v0.15.0
## What you did
When using DynamicScene to restore the state, StateScoped will not take effect. According to the code documentation, when the resources in the dynamic scene exist, the old value should be set to the new value, so in theory, the state transition should be triggered and then the StateScoped effect should be activated, but it is not expected to take effect.
## What went wrong
As expected, when restoring the state through DynamicScene, StateScoped should also be triggered
## Additional information
I made a demo according to the official scene example
KeyS: Save the scene
KeyL: Load the scene
KeyA: Set the state to A
KeyB: Set the state to B
The scene window will show:
Upper left corner: The text of the real state
Lower left corner: Run the text containing StateScoped through OnEnter
Operation:
Use S to save, then B to switch the state, and then L to load the state. The real state has changed, but StateScoped (StateA::A) is not cleared, and OnEnter (StateA::B) is not run.
```rust
use bevy::input::common_conditions::input_just_pressed;
use bevy::{prelude::*, tasks::IoTaskPool};
use std::{fs::File, io::Write};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.register_type_mutable_state::()
.init_state::()
.enable_state_scoped_entities::()
.add_systems(Startup, setup_camera)
.add_systems(Update, update_real_state)
.add_systems(OnEnter(StateA::A), infotext_a_system)
.add_systems(OnEnter(StateA::B), infotext_b_system)
.add_systems(Update, set_state)
.add_systems(
Update,
save_scene_system.run_if(input_just_pressed(KeyCode::KeyS)),
)
.add_systems(
Update,
load_scene_system.run_if(input_just_pressed(KeyCode::KeyL)),
)
.run();
}
#[derive(States, Reflect, Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
enum StateA {
#[default]
A,
B,
}
#[derive(Component, Reflect, Debug)]
#[reflect(Component)]
struct RealState;
const SCENE_FILE_PATH: &str = "scenes/test_states.scn.ron";
fn load_scene_system(mut commands: Commands, asset_server: Res) {
commands.spawn(DynamicSceneRoot(asset_server.load(SCENE_FILE_PATH)));
}
fn save_scene_system(world: &mut World) {
let scene = DynamicSceneBuilder::from_world(world)
.deny_all()
.allow_resource::>()
.extract_resources()
.build();
let type_registry = world.resource::();
let type_registry = type_registry.read();
let serialized_scene = scene.serialize(&type_registry).unwrap();
info!("{}", serialized_scene);
#[cfg(not(target_arch = "wasm32"))]
IoTaskPool::get()
.spawn(async move {
// Write the scene RON data to file
File::create(format!("assets/{SCENE_FILE_PATH}"))
.and_then(|mut file| file.write(serialized_scene.as_bytes()))
.expect("Error while writing scene to file");
})
.detach();
}
fn setup_camera(mut commands: Commands, state: Res>) {
commands.spawn(Camera2d);
commands.spawn((
Text::new(format!("Real State {:?}", state.get())),
TextFont {
font_size: 42.0,
..default()
},
Node {
align_self: AlignSelf::FlexStart,
..default()
},
RealState,
));
}
fn update_real_state(mut text: Single<&mut Text, With>, state: Res>) {
text.0 = format!("Real State {:?}", state.get());
}
fn infotext_a_system(mut commands: Commands, state: Res>) {
commands.spawn((
Text::new(format!("Current State {:?}", state.get())),
TextFont {
font_size: 42.0,
..default()
},
Node {
align_self: AlignSelf::FlexEnd,
..default()
},
StateScoped(StateA::A),
));
}
fn infotext_b_system(mut commands: Commands, state: Res>) {
commands.spawn((
Text::new(format!("Show State {:?}", state.get())),
TextFont {
font_size: 42.0,
..default()
},
Node {
align_self: AlignSelf::FlexEnd,
..default()
},
StateScoped(StateA::B),
));
}
fn set_state(input: Res>, mut state: ResMut>) {
if input.just_pressed(KeyCode::KeyA) {
state.set(StateA::A);
}
if input.just_pressed(KeyCode::KeyB) {
state.set(StateA::B);
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.