From 6e81a05c93781b8872bbeaa201d801906a0f912a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Sat, 16 Nov 2024 22:33:37 +0100 Subject: [PATCH] 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 --- Cargo.toml | 4 ++ crates/bevy_dev_tools/src/ci_testing/mod.rs | 2 +- crates/bevy_internal/Cargo.toml | 7 +-- crates/bevy_internal/src/default_plugins.rs | 55 ++------------------- crates/bevy_internal/src/lib.rs | 2 + crates/bevy_internal/src/prelude.rs | 7 ++- docs/cargo_features.md | 1 + examples/app/headless.rs | 23 ++++++--- 8 files changed, 38 insertions(+), 63 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 78ea868a52..897e751449 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,6 +125,7 @@ default = [ "bevy_text", "bevy_ui", "bevy_ui_picking_backend", + "bevy_window", "bevy_winit", "custom_cursor", "default_font", @@ -218,6 +219,9 @@ bevy_ui = [ "bevy_ui_picking_backend", ] +# Windowing layer +bevy_window = ["bevy_internal/bevy_window"] + # winit window and input backend bevy_winit = ["bevy_internal/bevy_winit"] diff --git a/crates/bevy_dev_tools/src/ci_testing/mod.rs b/crates/bevy_dev_tools/src/ci_testing/mod.rs index 18eeb6ba61..9f31db2140 100644 --- a/crates/bevy_dev_tools/src/ci_testing/mod.rs +++ b/crates/bevy_dev_tools/src/ci_testing/mod.rs @@ -17,7 +17,7 @@ use core::time::Duration; /// (`ci_testing_config.ron` by default) and executes its specified actions. For a reference of the /// 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. /// It is recommended to only used this plugin during testing (manual or /// automatic), and disable it during regular development and for production builds. diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 72535890bf..9e6cdebacc 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -97,7 +97,7 @@ serialize = [ "bevy_time/serialize", "bevy_transform/serialize", "bevy_ui?/serialize", - "bevy_window/serialize", + "bevy_window?/serialize", "bevy_winit?/serialize", ] multi_threaded = [ @@ -162,6 +162,7 @@ animation = ["bevy_animation", "bevy_gltf?/bevy_animation"] bevy_sprite = ["dep:bevy_sprite", "bevy_gizmos?/bevy_sprite"] 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 dynamic_linking = ["bevy_diagnostic/dynamic_linking"] @@ -248,7 +249,7 @@ ghost_nodes = ["bevy_ui/ghost_nodes"] [dependencies] # 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_core = { path = "../bevy_core", 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_transform = { path = "../bevy_transform", 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 (optional) bevy_animation = { path = "../bevy_animation", optional = true, version = "0.15.0-dev" } diff --git a/crates/bevy_internal/src/default_plugins.rs b/crates/bevy_internal/src/default_plugins.rs index 41754882c9..dee5e5960f 100644 --- a/crates/bevy_internal/src/default_plugins.rs +++ b/crates/bevy_internal/src/default_plugins.rs @@ -13,7 +13,11 @@ plugin_group! { bevy_hierarchy:::HierarchyPlugin, bevy_diagnostic:::DiagnosticsPlugin, bevy_input:::InputPlugin, + #[custom(cfg(not(feature = "bevy_window")))] + bevy_app:::ScheduleRunnerPlugin, + #[cfg(feature = "bevy_window")] bevy_window:::WindowPlugin, + #[cfg(feature = "bevy_window")] bevy_a11y:::AccessibilityPlugin, #[custom(cfg(not(target_arch = "wasm32")))] bevy_app:::TerminalCtrlCHandlerPlugin, @@ -72,55 +76,6 @@ plugin_group! { /// /// [`DefaultPlugins`] contains all the plugins typically required to build /// 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`]. } @@ -162,8 +117,6 @@ plugin_group! { } /// This plugin group represents the absolute minimum, bare-bones, bevy application. /// 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) /// to provide functionality that would otherwise be driven by a windowed application's diff --git a/crates/bevy_internal/src/lib.rs b/crates/bevy_internal/src/lib.rs index aa9ad4c830..dd7c351773 100644 --- a/crates/bevy_internal/src/lib.rs +++ b/crates/bevy_internal/src/lib.rs @@ -13,6 +13,7 @@ pub mod prelude; mod default_plugins; pub use default_plugins::*; +#[cfg(feature = "bevy_window")] pub use bevy_a11y as a11y; #[cfg(feature = "bevy_animation")] pub use bevy_animation as animation; @@ -66,6 +67,7 @@ pub use bevy_transform as transform; #[cfg(feature = "bevy_ui")] pub use bevy_ui as ui; pub use bevy_utils as utils; +#[cfg(feature = "bevy_window")] pub use bevy_window as window; #[cfg(feature = "bevy_winit")] pub use bevy_winit as winit; diff --git a/crates/bevy_internal/src/prelude.rs b/crates/bevy_internal/src/prelude.rs index 6d8830eb4d..a523488f65 100644 --- a/crates/bevy_internal/src/prelude.rs +++ b/crates/bevy_internal/src/prelude.rs @@ -2,10 +2,13 @@ pub use crate::{ app::prelude::*, core::prelude::*, ecs::prelude::*, hierarchy::prelude::*, input::prelude::*, log::prelude::*, math::prelude::*, reflect::prelude::*, time::prelude::*, - transform::prelude::*, utils::prelude::*, window::prelude::*, DefaultPlugins, HeadlessPlugins, - MinimalPlugins, + transform::prelude::*, utils::prelude::*, DefaultPlugins, MinimalPlugins, }; +#[doc(hidden)] +#[cfg(feature = "bevy_window")] +pub use crate::window::prelude::*; + #[doc(hidden)] #[cfg(feature = "bevy_image")] pub use crate::image::prelude::*; diff --git a/docs/cargo_features.md b/docs/cargo_features.md index 62f73f7c87..e9ad2e10c1 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -34,6 +34,7 @@ The default feature set enables most of the expected features of a game engine, |bevy_text|Provides text functionality| |bevy_ui|A custom ECS-driven UI framework| |bevy_ui_picking_backend|Provides an implementation for picking ui| +|bevy_window|Windowing layer| |bevy_winit|winit window and input backend| |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| diff --git a/examples/app/headless.rs b/examples/app/headless.rs index c6ee157b37..5bc2884b64 100644 --- a/examples/app/headless.rs +++ b/examples/app/headless.rs @@ -1,26 +1,37 @@ -//! This example only enables a minimal set of plugins required for bevy to run. -//! You can also completely remove rendering / windowing Plugin code from bevy -//! by making your import look like this in your Cargo.toml. +//! This example shows how to configure the `ScheduleRunnerPlugin` to run your +//! application without windowing. You can completely remove rendering / windowing +//! Plugin code from bevy by making your import look like this in your Cargo.toml. //! //! ```toml //! [dependencies] //! bevy = { version = "*", default-features = false } //! # replace "*" with the most recent version of bevy //! ``` - +//! +//! And then enabling the features you need. +//! See the full list: use bevy::{app::ScheduleRunnerPlugin, log::LogPlugin, prelude::*, utils::Duration}; 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 App::new() - .add_plugins(HeadlessPlugins.set(ScheduleRunnerPlugin::run_once())) + .add_plugins(DefaultPlugins.set(ScheduleRunnerPlugin::run_once())) .add_systems(Update, hello_world_system) .run(); // This app loops forever at 60 fps App::new() .add_plugins( - HeadlessPlugins + DefaultPlugins .set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64( 1.0 / 60.0, )))