Headless by features (#16401)

# Objective

- Fixes #16152 

## Solution

- Put `bevy_window` and `bevy_a11y` behind the `bevy_window` feature.
they were the only difference
- Add `ScheduleRunnerPlugin` to the `DefaultPlugins` when `bevy_window`
is disabled
- Remove `HeadlessPlugins`
- Update the `headless` example
This commit is contained in:
François Mockers 2024-11-16 22:33:37 +01:00 committed by GitHub
parent bce19c1012
commit 6e81a05c93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 38 additions and 63 deletions

View file

@ -125,6 +125,7 @@ default = [
"bevy_text", "bevy_text",
"bevy_ui", "bevy_ui",
"bevy_ui_picking_backend", "bevy_ui_picking_backend",
"bevy_window",
"bevy_winit", "bevy_winit",
"custom_cursor", "custom_cursor",
"default_font", "default_font",
@ -218,6 +219,9 @@ bevy_ui = [
"bevy_ui_picking_backend", "bevy_ui_picking_backend",
] ]
# Windowing layer
bevy_window = ["bevy_internal/bevy_window"]
# winit window and input backend # winit window and input backend
bevy_winit = ["bevy_internal/bevy_winit"] bevy_winit = ["bevy_internal/bevy_winit"]

View file

@ -17,7 +17,7 @@ use core::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`, `HeadlessPlugins` and `MinimalPlugins` /// This plugin is included within `DefaultPlugins` and `MinimalPlugins`
/// when the `bevy_ci_testing` feature is enabled. /// when the `bevy_ci_testing` feature is enabled.
/// It is recommended to only used this plugin during testing (manual or /// 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.

View file

@ -97,7 +97,7 @@ serialize = [
"bevy_time/serialize", "bevy_time/serialize",
"bevy_transform/serialize", "bevy_transform/serialize",
"bevy_ui?/serialize", "bevy_ui?/serialize",
"bevy_window/serialize", "bevy_window?/serialize",
"bevy_winit?/serialize", "bevy_winit?/serialize",
] ]
multi_threaded = [ multi_threaded = [
@ -162,6 +162,7 @@ animation = ["bevy_animation", "bevy_gltf?/bevy_animation"]
bevy_sprite = ["dep:bevy_sprite", "bevy_gizmos?/bevy_sprite"] bevy_sprite = ["dep:bevy_sprite", "bevy_gizmos?/bevy_sprite"]
bevy_pbr = ["dep:bevy_pbr", "bevy_gizmos?/bevy_pbr"] bevy_pbr = ["dep:bevy_pbr", "bevy_gizmos?/bevy_pbr"]
bevy_window = ["dep:bevy_window", "dep:bevy_a11y"]
# Used to disable code that is unsupported when Bevy is dynamically linked # Used to disable code that is unsupported when Bevy is dynamically linked
dynamic_linking = ["bevy_diagnostic/dynamic_linking"] dynamic_linking = ["bevy_diagnostic/dynamic_linking"]
@ -248,7 +249,7 @@ ghost_nodes = ["bevy_ui/ghost_nodes"]
[dependencies] [dependencies]
# bevy # bevy
bevy_a11y = { path = "../bevy_a11y", version = "0.15.0-dev" } bevy_a11y = { path = "../bevy_a11y", version = "0.15.0-dev", optional = true }
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" } bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
bevy_core = { path = "../bevy_core", version = "0.15.0-dev" } bevy_core = { path = "../bevy_core", version = "0.15.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" } bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
@ -266,7 +267,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
bevy_time = { path = "../bevy_time", version = "0.15.0-dev" } bevy_time = { path = "../bevy_time", version = "0.15.0-dev" }
bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" } bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
bevy_window = { path = "../bevy_window", version = "0.15.0-dev" } bevy_window = { path = "../bevy_window", version = "0.15.0-dev", optional = true }
bevy_tasks = { path = "../bevy_tasks", version = "0.15.0-dev" } bevy_tasks = { path = "../bevy_tasks", version = "0.15.0-dev" }
# bevy (optional) # bevy (optional)
bevy_animation = { path = "../bevy_animation", optional = true, version = "0.15.0-dev" } bevy_animation = { path = "../bevy_animation", optional = true, version = "0.15.0-dev" }

View file

@ -13,7 +13,11 @@ plugin_group! {
bevy_hierarchy:::HierarchyPlugin, bevy_hierarchy:::HierarchyPlugin,
bevy_diagnostic:::DiagnosticsPlugin, bevy_diagnostic:::DiagnosticsPlugin,
bevy_input:::InputPlugin, bevy_input:::InputPlugin,
#[custom(cfg(not(feature = "bevy_window")))]
bevy_app:::ScheduleRunnerPlugin,
#[cfg(feature = "bevy_window")]
bevy_window:::WindowPlugin, bevy_window:::WindowPlugin,
#[cfg(feature = "bevy_window")]
bevy_a11y:::AccessibilityPlugin, bevy_a11y:::AccessibilityPlugin,
#[custom(cfg(not(target_arch = "wasm32")))] #[custom(cfg(not(target_arch = "wasm32")))]
bevy_app:::TerminalCtrlCHandlerPlugin, bevy_app:::TerminalCtrlCHandlerPlugin,
@ -72,55 +76,6 @@ 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 [`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`]. /// For the absolute minimum number of plugins needed to run a Bevy application, see [`MinimalPlugins`].
} }
@ -162,8 +117,6 @@ plugin_group! {
} }
/// This plugin group represents the absolute minimum, bare-bones, bevy application. /// This plugin group represents the absolute minimum, bare-bones, bevy application.
/// Use this if you want to have absolute control over the plugins used. /// Use this if you want to have absolute control over the plugins used.
/// 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) /// 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

View file

@ -13,6 +13,7 @@ pub mod prelude;
mod default_plugins; mod default_plugins;
pub use default_plugins::*; pub use default_plugins::*;
#[cfg(feature = "bevy_window")]
pub use bevy_a11y as a11y; pub use bevy_a11y as a11y;
#[cfg(feature = "bevy_animation")] #[cfg(feature = "bevy_animation")]
pub use bevy_animation as animation; pub use bevy_animation as animation;
@ -66,6 +67,7 @@ pub use bevy_transform as transform;
#[cfg(feature = "bevy_ui")] #[cfg(feature = "bevy_ui")]
pub use bevy_ui as ui; pub use bevy_ui as ui;
pub use bevy_utils as utils; pub use bevy_utils as utils;
#[cfg(feature = "bevy_window")]
pub use bevy_window as window; pub use bevy_window as window;
#[cfg(feature = "bevy_winit")] #[cfg(feature = "bevy_winit")]
pub use bevy_winit as winit; pub use bevy_winit as winit;

View file

@ -2,10 +2,13 @@
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, HeadlessPlugins, transform::prelude::*, utils::prelude::*, DefaultPlugins, MinimalPlugins,
MinimalPlugins,
}; };
#[doc(hidden)]
#[cfg(feature = "bevy_window")]
pub use crate::window::prelude::*;
#[doc(hidden)] #[doc(hidden)]
#[cfg(feature = "bevy_image")] #[cfg(feature = "bevy_image")]
pub use crate::image::prelude::*; pub use crate::image::prelude::*;

View file

@ -34,6 +34,7 @@ The default feature set enables most of the expected features of a game engine,
|bevy_text|Provides text functionality| |bevy_text|Provides text functionality|
|bevy_ui|A custom ECS-driven UI framework| |bevy_ui|A custom ECS-driven UI framework|
|bevy_ui_picking_backend|Provides an implementation for picking ui| |bevy_ui_picking_backend|Provides an implementation for picking ui|
|bevy_window|Windowing layer|
|bevy_winit|winit window and input backend| |bevy_winit|winit window and input backend|
|custom_cursor|Enable winit custom cursor support| |custom_cursor|Enable winit custom cursor support|
|default_font|Include a default font, containing only ASCII characters, at the cost of a 20kB binary size increase| |default_font|Include a default font, containing only ASCII characters, at the cost of a 20kB binary size increase|

View file

@ -1,26 +1,37 @@
//! This example only enables a minimal set of plugins required for bevy to run. //! This example shows how to configure the `ScheduleRunnerPlugin` to run your
//! You can also completely remove rendering / windowing Plugin code from bevy //! application without windowing. You can completely remove rendering / windowing
//! by making your import look like this in your Cargo.toml. //! Plugin code from bevy by making your import look like this in your Cargo.toml.
//! //!
//! ```toml //! ```toml
//! [dependencies] //! [dependencies]
//! bevy = { version = "*", default-features = false } //! bevy = { version = "*", default-features = false }
//! # replace "*" with the most recent version of bevy //! # replace "*" with the most recent version of bevy
//! ``` //! ```
//!
//! And then enabling the features you need.
//! See the full list: <https://docs.rs/bevy/latest/bevy/#cargo-features>
use bevy::{app::ScheduleRunnerPlugin, log::LogPlugin, prelude::*, utils::Duration}; use bevy::{app::ScheduleRunnerPlugin, log::LogPlugin, prelude::*, utils::Duration};
fn main() { fn main() {
if cfg!(feature = "bevy_window") {
println!("This example is running with the bevy_window feature enabled and will not run headless.");
println!("Disable the default features and rerun the example to run headless.");
println!("To do so, run:");
println!();
println!(" cargo run --example headless --no-default-features");
return;
}
// This app runs once // This app runs once
App::new() App::new()
.add_plugins(HeadlessPlugins.set(ScheduleRunnerPlugin::run_once())) .add_plugins(DefaultPlugins.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(
HeadlessPlugins DefaultPlugins
.set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64( .set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(
1.0 / 60.0, 1.0 / 60.0,
))) )))