Added HeadlessPlugins (#15203) (#15260)

Added a `HeadlessPlugins` plugin group, that adds more default
functionality (like logging) than the `MinimumPlugins`. Fixes #15203
Changed the headless example to use the new plugin group.

I am not entirely sure if the list of plugins is correct. Are there ones
that should be added / removed?

----
The `TerminalCtrlCHandlerPlugin` has interesting effects in the headless
example: Installing it a second time it will give a log message about
skipping installation, because it is already installed. Ctrl+C will
terminate the application in that case. However, _not_ installing it the
second time (so only on the app that runs once) has the effect that the
app that runs continuously cannot be stopped using Ctrl+C.
This implies that, even though the second app did not install the Ctrl+C
handler, it did _something_ because it was keeping the one from the
first app alive.
Not sure if this is a problem or issue, or can be labeled a wierd quirk
of having multiple Apps in one executable.
This commit is contained in:
Wybe Westra 2024-09-19 18:44:43 +02:00 committed by GitHub
parent 7ad27f4759
commit 55c84cc722
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 71 additions and 15 deletions

View file

@ -17,8 +17,9 @@ use std::time::Duration;
/// (`ci_testing_config.ron` by default) and executes its specified actions. For a reference of the /// (`ci_testing_config.ron` by default) and executes its specified actions. For a reference of the
/// allowed configuration, see [`CiTestingConfig`]. /// allowed configuration, see [`CiTestingConfig`].
/// ///
/// This plugin is included within `DefaultPlugins` and `MinimalPlugins` when the `bevy_ci_testing` /// This plugin is included within `DefaultPlugins`, `HeadlessPlugins` and `MinimalPlugins`
/// feature is enabled. It is recommended to only used this plugin during testing (manual or /// when the `bevy_ci_testing` feature is enabled.
/// It is recommended to only used this plugin during testing (manual or
/// automatic), and disable it during regular development and for production builds. /// automatic), and disable it during regular development and for production builds.
#[derive(Default)] #[derive(Default)]
pub struct CiTestingPlugin; pub struct CiTestingPlugin;

View file

@ -71,7 +71,56 @@ plugin_group! {
/// ///
/// [`DefaultPlugins`] contains all the plugins typically required to build /// [`DefaultPlugins`] contains all the plugins typically required to build
/// a *Bevy* application which includes a *window* and presentation components. /// a *Bevy* application which includes a *window* and presentation components.
/// For *headless* cases without a *window* or presentation, see [`MinimalPlugins`]. /// For *headless* cases without a *window* or presentation, see [`HeadlessPlugins`].
/// For the absolute minimum number of plugins needed to run a Bevy application, see [`MinimalPlugins`].
}
plugin_group! {
/// This plugin group will add all the default plugins for a headless (no *window* or rendering) *Bevy* application:
pub struct HeadlessPlugins {
bevy_app:::PanicHandlerPlugin,
bevy_log:::LogPlugin,
bevy_core:::TaskPoolPlugin,
bevy_core:::TypeRegistrationPlugin,
bevy_core:::FrameCountPlugin,
bevy_time:::TimePlugin,
bevy_transform:::TransformPlugin,
bevy_hierarchy:::HierarchyPlugin,
bevy_diagnostic:::DiagnosticsPlugin,
bevy_app:::ScheduleRunnerPlugin,
#[custom(cfg(not(target_arch = "wasm32")))]
bevy_app:::TerminalCtrlCHandlerPlugin,
#[cfg(feature = "bevy_asset")]
bevy_asset:::AssetPlugin,
#[cfg(feature = "bevy_scene")]
bevy_scene:::ScenePlugin,
#[cfg(feature = "bevy_animation")]
bevy_animation:::AnimationPlugin,
#[cfg(feature = "bevy_state")]
bevy_state::app:::StatesPlugin,
#[cfg(feature = "bevy_ci_testing")]
bevy_dev_tools::ci_testing:::CiTestingPlugin,
#[doc(hidden)]
:IgnoreAmbiguitiesPlugin,
}
/// This group of plugins is intended for use for *headless* programs, for example: dedicated game servers.
/// See the [*Bevy* *headless* example](https://github.com/bevyengine/bevy/blob/main/examples/app/headless.rs)
///
/// [`HeadlessPlugins`] obeys *Cargo* *feature* flags. Users may exert control over this plugin group
/// by disabling `default-features` in their `Cargo.toml` and enabling only those features
/// that they wish to use.
///
/// [`HeadlessPlugins`] contains all the plugins typically required to build
/// a *Bevy* application. In contrast with [`DefaultPlugins`], it leaves out *window* and presentation components.
/// This allows applications built using this plugin group to run on devices that do not have a screen or rendering
/// capabilities.
/// It includes a [schedule runner (`ScheduleRunnerPlugin`)](crate::app::ScheduleRunnerPlugin)
/// to provide functionality that would otherwise be driven by a windowed application's
/// *event loop* or *message loop*.
///
/// Windowed applications that wish to use a reduced set of plugins should consider the
/// [`DefaultPlugins`] plugin group which can be controlled with *Cargo* *feature* flags.
/// For the absolute minimum number of plugins needed to run a Bevy application, see [`MinimalPlugins`].
} }
#[derive(Default)] #[derive(Default)]
@ -110,12 +159,12 @@ plugin_group! {
#[cfg(feature = "bevy_ci_testing")] #[cfg(feature = "bevy_ci_testing")]
bevy_dev_tools::ci_testing:::CiTestingPlugin, bevy_dev_tools::ci_testing:::CiTestingPlugin,
} }
/// This group of plugins is intended for use for minimal, *headless* programs /// This plugin group represents the absolute minimum, bare-bones, bevy application.
/// see the [*Bevy* *headless* example](https://github.com/bevyengine/bevy/blob/main/examples/app/headless.rs) /// Use this if you want to have absolute control over the plugins used.
/// and includes a [schedule runner (`ScheduleRunnerPlugin`)](crate::app::ScheduleRunnerPlugin) /// If you are looking to make a *headless* application - without a *window* or rendering,
/// it is usually best to use [`HeadlessPlugins`].
///
/// It includes a [schedule runner (`ScheduleRunnerPlugin`)](crate::app::ScheduleRunnerPlugin)
/// to provide functionality that would otherwise be driven by a windowed application's /// to provide functionality that would otherwise be driven by a windowed application's
/// *event loop* or *message loop*. /// *event loop* or *message loop*.
///
/// Windowed applications that wish to use a reduced set of plugins should consider the
/// [`DefaultPlugins`] plugin group which can be controlled with *Cargo* *feature* flags.
} }

View file

@ -2,7 +2,8 @@
pub use crate::{ pub use crate::{
app::prelude::*, core::prelude::*, ecs::prelude::*, hierarchy::prelude::*, input::prelude::*, app::prelude::*, core::prelude::*, ecs::prelude::*, hierarchy::prelude::*, input::prelude::*,
log::prelude::*, math::prelude::*, reflect::prelude::*, time::prelude::*, log::prelude::*, math::prelude::*, reflect::prelude::*, time::prelude::*,
transform::prelude::*, utils::prelude::*, window::prelude::*, DefaultPlugins, MinimalPlugins, transform::prelude::*, utils::prelude::*, window::prelude::*, DefaultPlugins, HeadlessPlugins,
MinimalPlugins,
}; };
pub use bevy_derive::{bevy_main, Deref, DerefMut}; pub use bevy_derive::{bevy_main, Deref, DerefMut};

View file

@ -8,21 +8,26 @@
//! # replace "*" with the most recent version of bevy //! # replace "*" with the most recent version of bevy
//! ``` //! ```
use bevy::{app::ScheduleRunnerPlugin, prelude::*, utils::Duration}; use bevy::{app::ScheduleRunnerPlugin, log::LogPlugin, prelude::*, utils::Duration};
fn main() { fn main() {
// This app runs once // This app runs once
App::new() App::new()
.add_plugins(MinimalPlugins.set(ScheduleRunnerPlugin::run_once())) .add_plugins(HeadlessPlugins.set(ScheduleRunnerPlugin::run_once()))
.add_systems(Update, hello_world_system) .add_systems(Update, hello_world_system)
.run(); .run();
// This app loops forever at 60 fps // This app loops forever at 60 fps
App::new() App::new()
.add_plugins( .add_plugins(
MinimalPlugins.set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64( HeadlessPlugins
.set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(
1.0 / 60.0, 1.0 / 60.0,
))), )))
// The log and ctrl+c plugin can only be registered once globally,
// which means we need to disable it here, because it was already registered with the
// app that runs once.
.disable::<LogPlugin>(),
) )
.add_systems(Update, counter) .add_systems(Update, counter)
.run(); .run();