Make bevy_app and reflect opt-out for bevy_hierarchy. (#10721)

# Objective

Bevy_hierarchy is very useful for ECS only usages of bevy_ecs, but it
currently pulls in bevy_reflect, bevy_app and bevy_core with no way to
opt out.

## Solution

This PR provides features `bevy_app` and `reflect` that are enabled by
default. If disabled, they should remove these dependencies from
bevy_hierarchy.

---

## Changelog

Added features `bevy_app` and `reflect` to bevy_hierarchy.
This commit is contained in:
Mincong Lu 2023-11-25 11:05:38 +08:00 committed by GitHub
parent 1065028154
commit c33bacd5fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 36 additions and 30 deletions

View File

@ -9,19 +9,20 @@ license = "MIT OR Apache-2.0"
keywords = ["bevy"] keywords = ["bevy"]
[features] [features]
default = ["bevy_app"]
trace = [] trace = []
bevy_app = ["reflect", "dep:bevy_app", "bevy_core", "bevy_log"]
reflect = ["bevy_ecs/bevy_reflect", "bevy_reflect"]
[dependencies] [dependencies]
# bevy # bevy
bevy_app = { path = "../bevy_app", version = "0.12.0" } bevy_app = { path = "../bevy_app", version = "0.12.0", optional = true }
bevy_core = { path = "../bevy_core", version = "0.12.0" } bevy_core = { path = "../bevy_core", version = "0.12.0", optional = true }
bevy_ecs = { path = "../bevy_ecs", version = "0.12.0", features = [ bevy_ecs = { path = "../bevy_ecs", version = "0.12.0", default-features = false }
"bevy_reflect", bevy_log = { path = "../bevy_log", version = "0.12.0", optional = true }
] }
bevy_log = { path = "../bevy_log", version = "0.12.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.12.0", features = [ bevy_reflect = { path = "../bevy_reflect", version = "0.12.0", features = [
"bevy", "bevy",
] } ], optional = true }
bevy_utils = { path = "../bevy_utils", version = "0.12.0" } bevy_utils = { path = "../bevy_utils", version = "0.12.0" }
# other # other

View File

@ -1,11 +1,11 @@
#[cfg(feature = "reflect")]
use bevy_ecs::reflect::{ReflectComponent, ReflectMapEntities};
use bevy_ecs::{ use bevy_ecs::{
component::Component, component::Component,
entity::{Entity, EntityMapper, MapEntities}, entity::{Entity, EntityMapper, MapEntities},
prelude::FromWorld, prelude::FromWorld,
reflect::{ReflectComponent, ReflectMapEntities},
world::World, world::World,
}; };
use bevy_reflect::Reflect;
use core::slice; use core::slice;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::ops::Deref; use std::ops::Deref;
@ -23,8 +23,9 @@ use std::ops::Deref;
/// [`Query`]: bevy_ecs::system::Query /// [`Query`]: bevy_ecs::system::Query
/// [`Parent`]: crate::components::parent::Parent /// [`Parent`]: crate::components::parent::Parent
/// [`BuildChildren::with_children`]: crate::child_builder::BuildChildren::with_children /// [`BuildChildren::with_children`]: crate::child_builder::BuildChildren::with_children
#[derive(Component, Debug, Reflect)] #[derive(Component, Debug)]
#[reflect(Component, MapEntities)] #[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "reflect", reflect(Component, MapEntities))]
pub struct Children(pub(crate) SmallVec<[Entity; 8]>); pub struct Children(pub(crate) SmallVec<[Entity; 8]>);
impl MapEntities for Children { impl MapEntities for Children {

View File

@ -1,10 +1,10 @@
#[cfg(feature = "reflect")]
use bevy_ecs::reflect::{ReflectComponent, ReflectMapEntities};
use bevy_ecs::{ use bevy_ecs::{
component::Component, component::Component,
entity::{Entity, EntityMapper, MapEntities}, entity::{Entity, EntityMapper, MapEntities},
reflect::{ReflectComponent, ReflectMapEntities},
world::{FromWorld, World}, world::{FromWorld, World},
}; };
use bevy_reflect::Reflect;
use std::ops::Deref; use std::ops::Deref;
/// Holds a reference to the parent entity of this entity. /// Holds a reference to the parent entity of this entity.
@ -20,8 +20,9 @@ use std::ops::Deref;
/// [`Query`]: bevy_ecs::system::Query /// [`Query`]: bevy_ecs::system::Query
/// [`Children`]: super::children::Children /// [`Children`]: super::children::Children
/// [`BuildChildren::with_children`]: crate::child_builder::BuildChildren::with_children /// [`BuildChildren::with_children`]: crate::child_builder::BuildChildren::with_children
#[derive(Component, Debug, Eq, PartialEq, Reflect)] #[derive(Component, Debug, Eq, PartialEq)]
#[reflect(Component, MapEntities, PartialEq)] #[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "reflect", reflect(Component, MapEntities, PartialEq))]
pub struct Parent(pub(crate) Entity); pub struct Parent(pub(crate) Entity);
impl Parent { impl Parent {

View File

@ -25,18 +25,21 @@ pub use query_extension::*;
#[doc(hidden)] #[doc(hidden)]
pub mod prelude { pub mod prelude {
#[doc(hidden)] #[doc(hidden)]
pub use crate::{ pub use crate::{child_builder::*, components::*, hierarchy::*, query_extension::*};
child_builder::*, components::*, hierarchy::*, query_extension::*, HierarchyPlugin,
ValidParentCheckPlugin, #[doc(hidden)]
}; #[cfg(feature = "bevy_app")]
pub use crate::{HierarchyPlugin, ValidParentCheckPlugin};
} }
#[cfg(feature = "bevy_app")]
use bevy_app::prelude::*; use bevy_app::prelude::*;
/// The base plugin for handling [`Parent`] and [`Children`] components /// The base plugin for handling [`Parent`] and [`Children`] components
#[derive(Default)] #[derive(Default)]
pub struct HierarchyPlugin; pub struct HierarchyPlugin;
#[cfg(feature = "bevy_app")]
impl Plugin for HierarchyPlugin { impl Plugin for HierarchyPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.register_type::<Children>() app.register_type::<Children>()

View File

@ -1,12 +1,10 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use bevy_app::{App, Last, Plugin}; #[cfg(feature = "bevy_app")]
use bevy_core::Name;
use bevy_ecs::prelude::*;
use bevy_log::warn;
use bevy_utils::{get_short_name, HashSet};
use crate::Parent; use crate::Parent;
use bevy_ecs::prelude::*;
#[cfg(feature = "bevy_app")]
use bevy_utils::{get_short_name, HashSet};
/// When enabled, runs [`check_hierarchy_component_has_valid_parent<T>`]. /// When enabled, runs [`check_hierarchy_component_has_valid_parent<T>`].
/// ///
@ -45,6 +43,7 @@ impl<T> Default for ReportHierarchyIssue<T> {
} }
} }
#[cfg(feature = "bevy_app")]
/// System to print a warning for each [`Entity`] with a `T` component /// System to print a warning for each [`Entity`] with a `T` component
/// which parent hasn't a `T` component. /// which parent hasn't a `T` component.
/// ///
@ -55,7 +54,7 @@ impl<T> Default for ReportHierarchyIssue<T> {
/// (See B0004 explanation linked in warning message) /// (See B0004 explanation linked in warning message)
pub fn check_hierarchy_component_has_valid_parent<T: Component>( pub fn check_hierarchy_component_has_valid_parent<T: Component>(
parent_query: Query< parent_query: Query<
(Entity, &Parent, Option<&Name>), (Entity, &Parent, Option<&bevy_core::Name>),
(With<T>, Or<(Changed<Parent>, Added<T>)>), (With<T>, Or<(Changed<Parent>, Added<T>)>),
>, >,
component_query: Query<(), With<T>>, component_query: Query<(), With<T>>,
@ -65,7 +64,7 @@ pub fn check_hierarchy_component_has_valid_parent<T: Component>(
let parent = parent.get(); let parent = parent.get();
if !component_query.contains(parent) && !already_diagnosed.contains(&entity) { if !component_query.contains(parent) && !already_diagnosed.contains(&entity) {
already_diagnosed.insert(entity); already_diagnosed.insert(entity);
warn!( bevy_log::warn!(
"warning[B0004]: {name} with the {ty_name} component has a parent without {ty_name}.\n\ "warning[B0004]: {name} with the {ty_name} component has a parent without {ty_name}.\n\
This will cause inconsistent behaviors! See https://bevyengine.org/learn/errors/#b0004", This will cause inconsistent behaviors! See https://bevyengine.org/learn/errors/#b0004",
ty_name = get_short_name(std::any::type_name::<T>()), ty_name = get_short_name(std::any::type_name::<T>()),
@ -94,10 +93,11 @@ impl<T: Component> Default for ValidParentCheckPlugin<T> {
} }
} }
impl<T: Component> Plugin for ValidParentCheckPlugin<T> { #[cfg(feature = "bevy_app")]
fn build(&self, app: &mut App) { impl<T: Component> bevy_app::Plugin for ValidParentCheckPlugin<T> {
fn build(&self, app: &mut bevy_app::App) {
app.init_resource::<ReportHierarchyIssue<T>>().add_systems( app.init_resource::<ReportHierarchyIssue<T>>().add_systems(
Last, bevy_app::Last,
check_hierarchy_component_has_valid_parent::<T> check_hierarchy_component_has_valid_parent::<T>
.run_if(resource_equals(ReportHierarchyIssue::<T>::new(true))), .run_if(resource_equals(ReportHierarchyIssue::<T>::new(true))),
); );