make bevy_text optional again (#7801)

# Objective

- `bevy_text` used to be "optional". the feature could be disabled, which meant that the systems were not added but `bevy_text` was still compiled because of a hard dependency in `bevy_ui`
- Running something without `bevy_text` enabled and with `bevy_ui` enabled now crashes:
```
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /bevy/crates/bevy_ecs/src/schedule/schedule.rs:1147:34
```
- This is because `bevy_ui` declares some of its systems in ambiguity sets with systems from `bevy_text`, which were not added if `bevy_text` is disabled

## Solution

- Make `bevy_text` completely optional

## Migration Guide

- feature `bevy_text` now completely removes `bevy_text` from the dependencies when not enabled. Enable feature `bevy_text` if you use Bevy to render text
This commit is contained in:
François 2023-02-24 02:21:07 +00:00
parent 695d30bd54
commit 1bd7306a3a
7 changed files with 68 additions and 46 deletions

View File

@ -82,6 +82,8 @@ dynamic_linking = ["bevy_diagnostic/dynamic_linking"]
# Enable using a shared stdlib for cxx on Android.
android_shared_stdcxx = ["bevy_audio/android_shared_stdcxx"]
bevy_text = ["dep:bevy_text", "bevy_ui?/bevy_text"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.9.0" }

View File

@ -24,7 +24,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.9.0", features = [
] }
bevy_render = { path = "../bevy_render", version = "0.9.0" }
bevy_sprite = { path = "../bevy_sprite", version = "0.9.0" }
bevy_text = { path = "../bevy_text", version = "0.9.0" }
bevy_text = { path = "../bevy_text", version = "0.9.0", optional = true }
bevy_transform = { path = "../bevy_transform", version = "0.9.0" }
bevy_window = { path = "../bevy_window", version = "0.9.0" }
bevy_utils = { path = "../bevy_utils", version = "0.9.0" }

View File

@ -14,7 +14,9 @@ pub mod node_bundles;
pub mod update;
pub mod widget;
use bevy_render::{camera::CameraUpdateSystem, extract_component::ExtractComponentPlugin};
#[cfg(feature = "bevy_text")]
use bevy_render::camera::CameraUpdateSystem;
use bevy_render::extract_component::ExtractComponentPlugin;
pub use flex::*;
pub use focus::*;
pub use geometry::*;
@ -103,44 +105,49 @@ impl Plugin for UiPlugin {
.configure_set(UiSystem::Focus.in_base_set(CoreSet::PreUpdate))
.configure_set(UiSystem::Flex.in_base_set(CoreSet::PostUpdate))
.configure_set(UiSystem::Stack.in_base_set(CoreSet::PostUpdate))
.add_system(ui_focus_system.in_set(UiSystem::Focus).after(InputSystem))
// add these systems to front because these must run before transform update systems
.add_system(
widget::text_system
.in_base_set(CoreSet::PostUpdate)
.before(UiSystem::Flex)
// Potential conflict: `Assets<Image>`
// In practice, they run independently since `bevy_render::camera_update_system`
// will only ever observe its own render target, and `widget::text_system`
// will never modify a pre-existing `Image` asset.
.ambiguous_with(CameraUpdateSystem)
// Potential conflict: `Assets<Image>`
// Since both systems will only ever insert new [`Image`] assets,
// they will never observe each other's effects.
.ambiguous_with(bevy_text::update_text2d_layout),
)
.add_system(
widget::update_image_calculated_size_system
.in_base_set(CoreSet::PostUpdate)
.before(UiSystem::Flex)
// Potential conflicts: `Assets<Image>`
// They run independently since `widget::image_node_system` will only ever observe
// its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout`
// will never modify a pre-existing `Image` asset.
.ambiguous_with(bevy_text::update_text2d_layout)
.ambiguous_with(widget::text_system),
)
.add_system(
flex_node_system
.in_set(UiSystem::Flex)
.before(TransformSystem::TransformPropagate),
)
.add_system(ui_stack_system.in_set(UiSystem::Stack))
.add_system(
update_clipping_system
.after(TransformSystem::TransformPropagate)
.in_base_set(CoreSet::PostUpdate),
);
.add_system(ui_focus_system.in_set(UiSystem::Focus).after(InputSystem));
// add these systems to front because these must run before transform update systems
#[cfg(feature = "bevy_text")]
app.add_system(
widget::text_system
.in_base_set(CoreSet::PostUpdate)
.before(UiSystem::Flex)
// Potential conflict: `Assets<Image>`
// In practice, they run independently since `bevy_render::camera_update_system`
// will only ever observe its own render target, and `widget::text_system`
// will never modify a pre-existing `Image` asset.
.ambiguous_with(CameraUpdateSystem)
// Potential conflict: `Assets<Image>`
// Since both systems will only ever insert new [`Image`] assets,
// they will never observe each other's effects.
.ambiguous_with(bevy_text::update_text2d_layout),
);
app.add_system({
let system = widget::update_image_calculated_size_system
.in_base_set(CoreSet::PostUpdate)
.before(UiSystem::Flex);
// Potential conflicts: `Assets<Image>`
// They run independently since `widget::image_node_system` will only ever observe
// its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout`
// will never modify a pre-existing `Image` asset.
#[cfg(feature = "bevy_text")]
let system = system
.ambiguous_with(bevy_text::update_text2d_layout)
.ambiguous_with(widget::text_system);
system
})
.add_system(
flex_node_system
.in_set(UiSystem::Flex)
.before(TransformSystem::TransformPropagate),
)
.add_system(ui_stack_system.in_set(UiSystem::Stack))
.add_system(
update_clipping_system
.after(TransformSystem::TransformPropagate)
.in_base_set(CoreSet::PostUpdate),
);
crate::render::build_ui_render(app);
}

View File

@ -9,6 +9,7 @@ use bevy_render::{
prelude::{Color, ComputedVisibility},
view::Visibility,
};
#[cfg(feature = "bevy_text")]
use bevy_text::{Text, TextAlignment, TextSection, TextStyle};
use bevy_transform::prelude::{GlobalTransform, Transform};
@ -95,6 +96,7 @@ pub struct ImageBundle {
pub z_index: ZIndex,
}
#[cfg(feature = "bevy_text")]
/// A UI node that is text
#[derive(Bundle, Clone, Debug)]
pub struct TextBundle {
@ -128,6 +130,7 @@ pub struct TextBundle {
pub background_color: BackgroundColor,
}
#[cfg(feature = "bevy_text")]
impl Default for TextBundle {
fn default() -> Self {
Self {
@ -147,6 +150,7 @@ impl Default for TextBundle {
}
}
#[cfg(feature = "bevy_text")]
impl TextBundle {
/// Create a [`TextBundle`] from a single section.
///

View File

@ -3,6 +3,7 @@ mod render_pass;
use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d};
use bevy_render::ExtractSchedule;
#[cfg(feature = "bevy_text")]
use bevy_window::{PrimaryWindow, Window};
pub use pipeline::*;
pub use render_pass::*;
@ -26,7 +27,10 @@ use bevy_render::{
view::{ComputedVisibility, ExtractedView, ViewUniforms},
Extract, RenderApp, RenderSet,
};
use bevy_sprite::{SpriteAssetEvents, TextureAtlas};
use bevy_sprite::SpriteAssetEvents;
#[cfg(feature = "bevy_text")]
use bevy_sprite::TextureAtlas;
#[cfg(feature = "bevy_text")]
use bevy_text::{Text, TextLayoutInfo};
use bevy_transform::components::GlobalTransform;
use bevy_utils::FloatOrd;
@ -78,6 +82,7 @@ pub fn build_ui_render(app: &mut App) {
extract_default_ui_camera_view::<Camera2d>,
extract_default_ui_camera_view::<Camera3d>,
extract_uinodes.in_set(RenderUiSystem::ExtractNode),
#[cfg(feature = "bevy_text")]
extract_text_uinodes.after(RenderUiSystem::ExtractNode),
),
)
@ -288,6 +293,7 @@ pub fn extract_default_ui_camera_view<T: Component>(
}
}
#[cfg(feature = "bevy_text")]
pub fn extract_text_uinodes(
mut extracted_uinodes: ResMut<ExtractedUiNodes>,
texture_atlases: Extract<Res<Assets<TextureAtlas>>>,

View File

@ -1,17 +1,18 @@
use crate::{CalculatedSize, UiImage};
use bevy_asset::Assets;
use bevy_ecs::{
query::Without,
system::{Query, Res},
};
#[cfg(feature = "bevy_text")]
use bevy_ecs::query::Without;
use bevy_ecs::system::{Query, Res};
use bevy_math::Vec2;
use bevy_render::texture::Image;
#[cfg(feature = "bevy_text")]
use bevy_text::Text;
/// Updates calculated size of the node based on the image provided
pub fn update_image_calculated_size_system(
textures: Res<Assets<Image>>,
mut query: Query<(&mut CalculatedSize, &UiImage), Without<Text>>,
#[cfg(feature = "bevy_text")] mut query: Query<(&mut CalculatedSize, &UiImage), Without<Text>>,
#[cfg(not(feature = "bevy_text"))] mut query: Query<(&mut CalculatedSize, &UiImage)>,
) {
for (mut calculated_size, image) in &mut query {
if let Some(texture) = textures.get(&image.texture) {

View File

@ -2,8 +2,10 @@
mod button;
mod image;
#[cfg(feature = "bevy_text")]
mod text;
pub use button::*;
pub use image::*;
#[cfg(feature = "bevy_text")]
pub use text::*;