mirror of
https://github.com/bevyengine/bevy
synced 2024-12-22 19:13:08 +00:00
0c7df881e7
# Objective Spamming the window close button on window may trigger a panic. ``` thread 'main' panicked at <Bevy repo>\crates\bevy_ecs\src\system\commands\mod.rs:1320:13: error[B0003]: Could not insert a bundle (of type `bevy_window:🪟:ClosingWindow`) for entity 0v1#4294967296 because it doesn't exist in this World. See: https://bevyengine.org/learn/errors/b0003 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Encountered a panic when applying buffers for system `bevy_window::system::close_when_requested`! 2024-08-01T15:00:29.742612Z WARN bevy_ecs::world::command_queue: CommandQueue has un-applied commands being dropped. Did you forget to call SystemState::apply? Encountered a panic in system `bevy_app::main_schedule::Main::run_main`! error: process didn't exit successfully: `target\debug\bevy.exe` (exit code: 101) ``` ## Solution Don't panic when trying to insert the `ClosingWindow` component into a entity. ## Testing Found and tested on windows. I haven't checked if this bug happens on linux or macos. For testing I ran this code: ```rust use std::{thread, time::Duration}; use bevy::prelude::*; fn lag() { thread::sleep(Duration::from_millis(300)); } fn main() -> AppExit { App::new() .add_plugins(DefaultPlugins) .add_systems(Update, lag) .run() } ``` Then spammed the window close button. The panic no longer occurs.
58 lines
2.3 KiB
Rust
58 lines
2.3 KiB
Rust
use crate::{ClosingWindow, PrimaryWindow, Window, WindowCloseRequested};
|
|
|
|
use bevy_app::AppExit;
|
|
use bevy_ecs::prelude::*;
|
|
|
|
/// Exit the application when there are no open windows.
|
|
///
|
|
/// This system is added by the [`WindowPlugin`] in the default configuration.
|
|
/// To disable this behavior, set `close_when_requested` (on the [`WindowPlugin`]) to `false`.
|
|
/// Ensure that you read the caveats documented on that field if doing so.
|
|
///
|
|
/// [`WindowPlugin`]: crate::WindowPlugin
|
|
pub fn exit_on_all_closed(mut app_exit_events: EventWriter<AppExit>, windows: Query<&Window>) {
|
|
if windows.is_empty() {
|
|
bevy_utils::tracing::info!("No windows are open, exiting");
|
|
app_exit_events.send(AppExit::Success);
|
|
}
|
|
}
|
|
|
|
/// Exit the application when the primary window has been closed
|
|
///
|
|
/// This system is added by the [`WindowPlugin`]
|
|
///
|
|
/// [`WindowPlugin`]: crate::WindowPlugin
|
|
pub fn exit_on_primary_closed(
|
|
mut app_exit_events: EventWriter<AppExit>,
|
|
windows: Query<(), (With<Window>, With<PrimaryWindow>)>,
|
|
) {
|
|
if windows.is_empty() {
|
|
bevy_utils::tracing::info!("Primary window was closed, exiting");
|
|
app_exit_events.send(AppExit::Success);
|
|
}
|
|
}
|
|
|
|
/// Close windows in response to [`WindowCloseRequested`] (e.g. when the close button is pressed).
|
|
///
|
|
/// This system is added by the [`WindowPlugin`] in the default configuration.
|
|
/// To disable this behavior, set `close_when_requested` (on the [`WindowPlugin`]) to `false`.
|
|
/// Ensure that you read the caveats documented on that field if doing so.
|
|
///
|
|
/// [`WindowPlugin`]: crate::WindowPlugin
|
|
pub fn close_when_requested(
|
|
mut commands: Commands,
|
|
mut closed: EventReader<WindowCloseRequested>,
|
|
closing: Query<Entity, With<ClosingWindow>>,
|
|
) {
|
|
// This was inserted by us on the last frame so now we can despawn the window
|
|
for window in closing.iter() {
|
|
commands.entity(window).despawn();
|
|
}
|
|
// Mark the window as closing so we can despawn it on the next frame
|
|
for event in closed.read() {
|
|
// When spamming the window close button on windows (other platforms too probably)
|
|
// we may receive a `WindowCloseRequested` for a window we've just despawned in the above
|
|
// loop.
|
|
commands.entity(event.window).try_insert(ClosingWindow);
|
|
}
|
|
}
|