mirror of
https://github.com/bevyengine/bevy
synced 2025-02-17 22:48:38 +00:00
Implement Sub-App Labels (#2695)
This is a rather simple but wide change, and it involves adding a new `bevy_app_macros` crate. Let me know if there is a better way to do any of this! --- # Objective - Allow adding and accessing sub-apps by using a label instead of an index ## Solution - Migrate the bevy label implementation and derive code to the `bevy_utils` and `bevy_macro_utils` crates and then add a new `SubAppLabel` trait to the `bevy_app` crate that is used when adding or getting a sub-app from an app.
This commit is contained in:
parent
c3d3ae7f92
commit
e290a7e29c
21 changed files with 244 additions and 168 deletions
|
@ -23,6 +23,7 @@ bevy_derive = { path = "../bevy_derive", version = "0.5.0" }
|
||||||
bevy_ecs = { path = "../bevy_ecs", version = "0.5.0" }
|
bevy_ecs = { path = "../bevy_ecs", version = "0.5.0" }
|
||||||
bevy_reflect = { path = "../bevy_reflect", version = "0.5.0", optional = true }
|
bevy_reflect = { path = "../bevy_reflect", version = "0.5.0", optional = true }
|
||||||
bevy_utils = { path = "../bevy_utils", version = "0.5.0" }
|
bevy_utils = { path = "../bevy_utils", version = "0.5.0" }
|
||||||
|
bevy_app_macros = { path = "./macros", version = "0.5.0" }
|
||||||
|
|
||||||
# other
|
# other
|
||||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||||
|
|
16
crates/bevy_app/macros/Cargo.toml
Normal file
16
crates/bevy_app/macros/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "bevy_app_macros"
|
||||||
|
version = "0.5.0"
|
||||||
|
description = "Bevy App Macros"
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.5.0" }
|
||||||
|
|
||||||
|
syn = "1.0"
|
||||||
|
quote = "1.0"
|
||||||
|
proc-macro2 = "1.0"
|
19
crates/bevy_app/macros/src/lib.rs
Normal file
19
crates/bevy_app/macros/src/lib.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use bevy_macro_utils::{derive_label, BevyManifest};
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::format_ident;
|
||||||
|
|
||||||
|
#[proc_macro_derive(SubAppLabel)]
|
||||||
|
pub fn derive_sub_app_label(input: TokenStream) -> TokenStream {
|
||||||
|
let input = syn::parse_macro_input!(input as syn::DeriveInput);
|
||||||
|
let mut trait_path = bevy_app_path();
|
||||||
|
trait_path
|
||||||
|
.segments
|
||||||
|
.push(format_ident!("SubAppLabel").into());
|
||||||
|
derive_label(input, trait_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bevy_app_path() -> syn::Path {
|
||||||
|
BevyManifest::default().get_path("bevy_app")
|
||||||
|
}
|
|
@ -7,12 +7,17 @@ use bevy_ecs::{
|
||||||
},
|
},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_utils::tracing::debug;
|
use bevy_utils::{tracing::debug, HashMap};
|
||||||
use std::{fmt::Debug, hash::Hash};
|
use std::{fmt::Debug, hash::Hash};
|
||||||
|
|
||||||
|
pub use bevy_app_macros::SubAppLabel;
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use bevy_utils::tracing::info_span;
|
use bevy_utils::tracing::info_span;
|
||||||
|
|
||||||
|
bevy_utils::define_label!(SubAppLabel);
|
||||||
|
type BoxedSubAppLabel = Box<dyn SubAppLabel>;
|
||||||
|
|
||||||
#[allow(clippy::needless_doctest_main)]
|
#[allow(clippy::needless_doctest_main)]
|
||||||
/// Containers of app logic and data
|
/// Containers of app logic and data
|
||||||
///
|
///
|
||||||
|
@ -40,7 +45,7 @@ pub struct App {
|
||||||
pub world: World,
|
pub world: World,
|
||||||
pub runner: Box<dyn Fn(App)>,
|
pub runner: Box<dyn Fn(App)>,
|
||||||
pub schedule: Schedule,
|
pub schedule: Schedule,
|
||||||
sub_apps: Vec<SubApp>,
|
sub_apps: HashMap<BoxedSubAppLabel, SubApp>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SubApp {
|
struct SubApp {
|
||||||
|
@ -77,7 +82,7 @@ impl App {
|
||||||
world: Default::default(),
|
world: Default::default(),
|
||||||
schedule: Default::default(),
|
schedule: Default::default(),
|
||||||
runner: Box::new(run_once),
|
runner: Box::new(run_once),
|
||||||
sub_apps: Vec::new(),
|
sub_apps: HashMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +92,7 @@ impl App {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _bevy_frame_update_guard = bevy_frame_update_span.enter();
|
let _bevy_frame_update_guard = bevy_frame_update_span.enter();
|
||||||
self.schedule.run(&mut self.world);
|
self.schedule.run(&mut self.world);
|
||||||
for sub_app in self.sub_apps.iter_mut() {
|
for sub_app in self.sub_apps.values_mut() {
|
||||||
(sub_app.runner)(&mut self.world, &mut sub_app.app);
|
(sub_app.runner)(&mut self.world, &mut sub_app.app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -589,19 +594,25 @@ impl App {
|
||||||
|
|
||||||
pub fn add_sub_app(
|
pub fn add_sub_app(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
label: impl SubAppLabel,
|
||||||
app: App,
|
app: App,
|
||||||
f: impl Fn(&mut World, &mut App) + 'static,
|
f: impl Fn(&mut World, &mut App) + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.sub_apps.push(SubApp {
|
self.sub_apps.insert(
|
||||||
app,
|
Box::new(label),
|
||||||
runner: Box::new(f),
|
SubApp {
|
||||||
});
|
app,
|
||||||
|
runner: Box::new(f),
|
||||||
|
},
|
||||||
|
);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use labels instead of indices
|
pub fn sub_app_mut(&mut self, label: impl SubAppLabel) -> Option<&mut App> {
|
||||||
pub fn sub_app_mut(&mut self, index: usize) -> &mut App {
|
let label = Box::new(label) as BoxedSubAppLabel;
|
||||||
&mut self.sub_apps[index].app
|
self.sub_apps
|
||||||
|
.get_mut(&label)
|
||||||
|
.map(|sub_app| &mut sub_app.app)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
name = "bevy_ecs_macros"
|
name = "bevy_ecs_macros"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
description = "Bevy ECS Macros"
|
description = "Bevy ECS Macros"
|
||||||
authors = [
|
|
||||||
"Bevy Contributors <bevyengine@gmail.com>",
|
|
||||||
"Carter Anderson <mcanders1@gmail.com>",
|
|
||||||
]
|
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use bevy_macro_utils::BevyManifest;
|
use bevy_macro_utils::{derive_label, BevyManifest};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
use proc_macro2::Span;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
|
@ -10,7 +10,7 @@ use syn::{
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
token::Comma,
|
token::Comma,
|
||||||
Data, DataStruct, DeriveInput, Field, Fields, GenericParam, Ident, Index, Lifetime, LitInt,
|
Data, DataStruct, DeriveInput, Field, Fields, GenericParam, Ident, Index, Lifetime, LitInt,
|
||||||
Path, Result, Token,
|
Result, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AllTuples {
|
struct AllTuples {
|
||||||
|
@ -436,46 +436,43 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
||||||
#[proc_macro_derive(SystemLabel)]
|
#[proc_macro_derive(SystemLabel)]
|
||||||
pub fn derive_system_label(input: TokenStream) -> TokenStream {
|
pub fn derive_system_label(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
let mut trait_path = bevy_ecs_path();
|
||||||
derive_label(input, Ident::new("SystemLabel", Span::call_site())).into()
|
trait_path.segments.push(format_ident!("schedule").into());
|
||||||
|
trait_path
|
||||||
|
.segments
|
||||||
|
.push(format_ident!("SystemLabel").into());
|
||||||
|
derive_label(input, trait_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(StageLabel)]
|
#[proc_macro_derive(StageLabel)]
|
||||||
pub fn derive_stage_label(input: TokenStream) -> TokenStream {
|
pub fn derive_stage_label(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
derive_label(input, Ident::new("StageLabel", Span::call_site())).into()
|
let mut trait_path = bevy_ecs_path();
|
||||||
|
trait_path.segments.push(format_ident!("schedule").into());
|
||||||
|
trait_path.segments.push(format_ident!("StageLabel").into());
|
||||||
|
derive_label(input, trait_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(AmbiguitySetLabel)]
|
#[proc_macro_derive(AmbiguitySetLabel)]
|
||||||
pub fn derive_ambiguity_set_label(input: TokenStream) -> TokenStream {
|
pub fn derive_ambiguity_set_label(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
derive_label(input, Ident::new("AmbiguitySetLabel", Span::call_site())).into()
|
let mut trait_path = bevy_ecs_path();
|
||||||
|
trait_path.segments.push(format_ident!("schedule").into());
|
||||||
|
trait_path
|
||||||
|
.segments
|
||||||
|
.push(format_ident!("AmbiguitySetLabel").into());
|
||||||
|
derive_label(input, trait_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(RunCriteriaLabel)]
|
#[proc_macro_derive(RunCriteriaLabel)]
|
||||||
pub fn derive_run_criteria_label(input: TokenStream) -> TokenStream {
|
pub fn derive_run_criteria_label(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
derive_label(input, Ident::new("RunCriteriaLabel", Span::call_site())).into()
|
let mut trait_path = bevy_ecs_path();
|
||||||
}
|
trait_path.segments.push(format_ident!("schedule").into());
|
||||||
|
trait_path
|
||||||
fn derive_label(input: DeriveInput, label_type: Ident) -> TokenStream2 {
|
.segments
|
||||||
let ident = input.ident;
|
.push(format_ident!("RunCriteriaLabel").into());
|
||||||
let ecs_path: Path = bevy_ecs_path();
|
derive_label(input, trait_path)
|
||||||
|
|
||||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
|
||||||
let mut where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause {
|
|
||||||
where_token: Default::default(),
|
|
||||||
predicates: Default::default(),
|
|
||||||
});
|
|
||||||
where_clause.predicates.push(syn::parse2(quote! { Self: Eq + ::std::fmt::Debug + ::std::hash::Hash + Clone + Send + Sync + 'static }).unwrap());
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
impl #impl_generics #ecs_path::schedule::#label_type for #ident #ty_generics #where_clause {
|
|
||||||
fn dyn_clone(&self) -> Box<dyn #ecs_path::schedule::#label_type> {
|
|
||||||
Box::new(Clone::clone(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bevy_ecs_path() -> syn::Path {
|
fn bevy_ecs_path() -> syn::Path {
|
||||||
|
|
|
@ -1,115 +1,15 @@
|
||||||
pub use bevy_ecs_macros::{AmbiguitySetLabel, RunCriteriaLabel, StageLabel, SystemLabel};
|
pub use bevy_ecs_macros::{AmbiguitySetLabel, RunCriteriaLabel, StageLabel, SystemLabel};
|
||||||
|
|
||||||
use std::{
|
use bevy_utils::define_label;
|
||||||
any::Any,
|
|
||||||
borrow::Cow,
|
|
||||||
fmt::Debug,
|
|
||||||
hash::{Hash, Hasher},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait DynEq: Any {
|
define_label!(StageLabel);
|
||||||
fn as_any(&self) -> &dyn Any;
|
|
||||||
|
|
||||||
fn dyn_eq(&self, other: &dyn DynEq) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> DynEq for T
|
|
||||||
where
|
|
||||||
T: Any + Eq,
|
|
||||||
{
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dyn_eq(&self, other: &dyn DynEq) -> bool {
|
|
||||||
if let Some(other) = other.as_any().downcast_ref::<T>() {
|
|
||||||
return self == other;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait DynHash: DynEq {
|
|
||||||
fn as_dyn_eq(&self) -> &dyn DynEq;
|
|
||||||
|
|
||||||
fn dyn_hash(&self, state: &mut dyn Hasher);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> DynHash for T
|
|
||||||
where
|
|
||||||
T: DynEq + Hash,
|
|
||||||
{
|
|
||||||
fn as_dyn_eq(&self) -> &dyn DynEq {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
|
|
||||||
T::hash(self, &mut state);
|
|
||||||
self.type_id().hash(&mut state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait StageLabel: DynHash + Debug + Send + Sync + 'static {
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn dyn_clone(&self) -> Box<dyn StageLabel>;
|
|
||||||
}
|
|
||||||
pub(crate) type BoxedStageLabel = Box<dyn StageLabel>;
|
pub(crate) type BoxedStageLabel = Box<dyn StageLabel>;
|
||||||
|
|
||||||
pub trait SystemLabel: DynHash + Debug + Send + Sync + 'static {
|
define_label!(SystemLabel);
|
||||||
#[doc(hidden)]
|
|
||||||
fn dyn_clone(&self) -> Box<dyn SystemLabel>;
|
|
||||||
}
|
|
||||||
pub(crate) type BoxedSystemLabel = Box<dyn SystemLabel>;
|
pub(crate) type BoxedSystemLabel = Box<dyn SystemLabel>;
|
||||||
|
|
||||||
pub trait AmbiguitySetLabel: DynHash + Debug + Send + Sync + 'static {
|
define_label!(AmbiguitySetLabel);
|
||||||
#[doc(hidden)]
|
|
||||||
fn dyn_clone(&self) -> Box<dyn AmbiguitySetLabel>;
|
|
||||||
}
|
|
||||||
pub(crate) type BoxedAmbiguitySetLabel = Box<dyn AmbiguitySetLabel>;
|
pub(crate) type BoxedAmbiguitySetLabel = Box<dyn AmbiguitySetLabel>;
|
||||||
|
|
||||||
pub trait RunCriteriaLabel: DynHash + Debug + Send + Sync + 'static {
|
define_label!(RunCriteriaLabel);
|
||||||
#[doc(hidden)]
|
|
||||||
fn dyn_clone(&self) -> Box<dyn RunCriteriaLabel>;
|
|
||||||
}
|
|
||||||
pub(crate) type BoxedRunCriteriaLabel = Box<dyn RunCriteriaLabel>;
|
pub(crate) type BoxedRunCriteriaLabel = Box<dyn RunCriteriaLabel>;
|
||||||
|
|
||||||
macro_rules! impl_label {
|
|
||||||
($trait_name:ident) => {
|
|
||||||
impl PartialEq for dyn $trait_name {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.dyn_eq(other.as_dyn_eq())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for dyn $trait_name {}
|
|
||||||
|
|
||||||
impl Hash for dyn $trait_name {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
self.dyn_hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for Box<dyn $trait_name> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
self.dyn_clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $trait_name for Cow<'static, str> {
|
|
||||||
fn dyn_clone(&self) -> Box<dyn $trait_name> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $trait_name for &'static str {
|
|
||||||
fn dyn_clone(&self) -> Box<dyn $trait_name> {
|
|
||||||
Box::new(<&str>::clone(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_label!(StageLabel);
|
|
||||||
impl_label!(SystemLabel);
|
|
||||||
impl_label!(AmbiguitySetLabel);
|
|
||||||
impl_label!(RunCriteriaLabel);
|
|
||||||
|
|
|
@ -15,3 +15,4 @@ keywords = ["bevy"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cargo-manifest = "0.2.3"
|
cargo-manifest = "0.2.3"
|
||||||
syn = "1.0"
|
syn = "1.0"
|
||||||
|
quote = "1.0"
|
||||||
|
|
|
@ -2,6 +2,7 @@ extern crate proc_macro;
|
||||||
|
|
||||||
use cargo_manifest::{DepsSet, Manifest};
|
use cargo_manifest::{DepsSet, Manifest};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
use std::{env, path::PathBuf};
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
pub struct BevyManifest {
|
pub struct BevyManifest {
|
||||||
|
@ -59,3 +60,29 @@ fn get_path(path: &str) -> syn::Path {
|
||||||
fn parse_str<T: syn::parse::Parse>(path: &str) -> T {
|
fn parse_str<T: syn::parse::Parse>(path: &str) -> T {
|
||||||
syn::parse(path.parse::<TokenStream>().unwrap()).unwrap()
|
syn::parse(path.parse::<TokenStream>().unwrap()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derive a label trait
|
||||||
|
///
|
||||||
|
/// # Args
|
||||||
|
///
|
||||||
|
/// - `input`: The [`syn::DeriveInput`] for struct that is deriving the label trait
|
||||||
|
/// - `trait_path`: The path [`syn::Path`] to the label trait
|
||||||
|
pub fn derive_label(input: syn::DeriveInput, trait_path: syn::Path) -> TokenStream {
|
||||||
|
let ident = input.ident;
|
||||||
|
|
||||||
|
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||||
|
let mut where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause {
|
||||||
|
where_token: Default::default(),
|
||||||
|
predicates: Default::default(),
|
||||||
|
});
|
||||||
|
where_clause.predicates.push(syn::parse2(quote! { Self: Eq + ::std::fmt::Debug + ::std::hash::Hash + Clone + Send + Sync + 'static }).unwrap());
|
||||||
|
|
||||||
|
(quote! {
|
||||||
|
impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
|
||||||
|
fn dyn_clone(&self) -> Box<dyn #trait_path> {
|
||||||
|
Box::new(Clone::clone(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
100
crates/bevy_utils/src/label.rs
Normal file
100
crates/bevy_utils/src/label.rs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
//! Traits used by label implementations
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
any::Any,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait DynEq: Any {
|
||||||
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
fn dyn_eq(&self, other: &dyn DynEq) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DynEq for T
|
||||||
|
where
|
||||||
|
T: Any + Eq,
|
||||||
|
{
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dyn_eq(&self, other: &dyn DynEq) -> bool {
|
||||||
|
if let Some(other) = other.as_any().downcast_ref::<T>() {
|
||||||
|
return self == other;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DynHash: DynEq {
|
||||||
|
fn as_dyn_eq(&self) -> &dyn DynEq;
|
||||||
|
|
||||||
|
fn dyn_hash(&self, state: &mut dyn Hasher);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DynHash for T
|
||||||
|
where
|
||||||
|
T: DynEq + Hash,
|
||||||
|
{
|
||||||
|
fn as_dyn_eq(&self) -> &dyn DynEq {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
|
||||||
|
T::hash(self, &mut state);
|
||||||
|
self.type_id().hash(&mut state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Macro to define a new label trait
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_utils::define_label;
|
||||||
|
/// define_label!(MyNewLabelTrait);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! define_label {
|
||||||
|
($label_trait_name:ident) => {
|
||||||
|
pub trait $label_trait_name:
|
||||||
|
::bevy_utils::label::DynHash + ::std::fmt::Debug + Send + Sync + 'static
|
||||||
|
{
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn dyn_clone(&self) -> Box<dyn $label_trait_name>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for dyn $label_trait_name {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.dyn_eq(other.as_dyn_eq())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for dyn $label_trait_name {}
|
||||||
|
|
||||||
|
impl ::std::hash::Hash for dyn $label_trait_name {
|
||||||
|
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.dyn_hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Box<dyn $label_trait_name> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
self.dyn_clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $label_trait_name for ::std::borrow::Cow<'static, str> {
|
||||||
|
fn dyn_clone(&self) -> Box<dyn $label_trait_name> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $label_trait_name for &'static str {
|
||||||
|
fn dyn_clone(&self) -> Box<dyn $label_trait_name> {
|
||||||
|
Box::new(<&str>::clone(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
mod enum_variant_meta;
|
mod enum_variant_meta;
|
||||||
|
pub mod label;
|
||||||
pub mod slab;
|
pub mod slab;
|
||||||
|
|
||||||
pub use ahash::AHasher;
|
pub use ahash::AHasher;
|
||||||
|
|
|
@ -20,7 +20,7 @@ use bevy_render2::{
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::TextureCache,
|
texture::TextureCache,
|
||||||
view::{ExtractedView, ViewPlugin},
|
view::{ExtractedView, ViewPlugin},
|
||||||
RenderStage, RenderWorld,
|
RenderStage, RenderSubApp, RenderWorld,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Resource that configures the clear color
|
/// Resource that configures the clear color
|
||||||
|
@ -74,7 +74,7 @@ impl Plugin for CorePipelinePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<ClearColor>();
|
app.init_resource::<ClearColor>();
|
||||||
|
|
||||||
let render_app = app.sub_app_mut(0);
|
let render_app = app.sub_app_mut(RenderSubApp).unwrap();
|
||||||
render_app
|
render_app
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_clear_color)
|
.add_system_to_stage(RenderStage::Extract, extract_clear_color)
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_core_pipeline_camera_phases)
|
.add_system_to_stage(RenderStage::Extract, extract_core_pipeline_camera_phases)
|
||||||
|
|
|
@ -13,7 +13,7 @@ use bevy_ecs::prelude::*;
|
||||||
use bevy_render2::{
|
use bevy_render2::{
|
||||||
render_graph::RenderGraph,
|
render_graph::RenderGraph,
|
||||||
render_phase::{sort_phase_system, DrawFunctions},
|
render_phase::{sort_phase_system, DrawFunctions},
|
||||||
RenderStage,
|
RenderStage, RenderSubApp,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod draw_3d_graph {
|
pub mod draw_3d_graph {
|
||||||
|
@ -30,7 +30,7 @@ impl Plugin for PbrPlugin {
|
||||||
app.add_plugin(StandardMaterialPlugin)
|
app.add_plugin(StandardMaterialPlugin)
|
||||||
.init_resource::<AmbientLight>();
|
.init_resource::<AmbientLight>();
|
||||||
|
|
||||||
let render_app = app.sub_app_mut(0);
|
let render_app = app.sub_app_mut(RenderSubApp).unwrap();
|
||||||
render_app
|
render_app
|
||||||
.add_system_to_stage(RenderStage::Extract, render::extract_meshes)
|
.add_system_to_stage(RenderStage::Extract, render::extract_meshes)
|
||||||
.add_system_to_stage(RenderStage::Extract, render::extract_lights)
|
.add_system_to_stage(RenderStage::Extract, render::extract_lights)
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub use bundle::*;
|
||||||
pub use camera::*;
|
pub use camera::*;
|
||||||
pub use projection::*;
|
pub use projection::*;
|
||||||
|
|
||||||
use crate::{view::ExtractedView, RenderStage};
|
use crate::{view::ExtractedView, RenderStage, RenderSubApp};
|
||||||
use bevy_app::{App, CoreStage, Plugin};
|
use bevy_app::{App, CoreStage, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ impl Plugin for CameraPlugin {
|
||||||
CoreStage::PostUpdate,
|
CoreStage::PostUpdate,
|
||||||
crate::camera::camera_system::<PerspectiveProjection>,
|
crate::camera::camera_system::<PerspectiveProjection>,
|
||||||
);
|
);
|
||||||
let render_app = app.sub_app_mut(0);
|
let render_app = app.sub_app_mut(RenderSubApp).unwrap();
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<ExtractedCameraNames>()
|
.init_resource::<ExtractedCameraNames>()
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_cameras);
|
.add_system_to_stage(RenderStage::Extract, extract_cameras);
|
||||||
|
|
|
@ -24,7 +24,7 @@ use crate::{
|
||||||
texture::ImagePlugin,
|
texture::ImagePlugin,
|
||||||
view::{ViewPlugin, WindowRenderPlugin},
|
view::{ViewPlugin, WindowRenderPlugin},
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin, SubAppLabel};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -73,6 +73,10 @@ impl DerefMut for RenderWorld {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Label for the rendering sub-app
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, SubAppLabel)]
|
||||||
|
pub struct RenderSubApp;
|
||||||
|
|
||||||
/// A "scratch" world used to avoid allocating new worlds every frame when
|
/// A "scratch" world used to avoid allocating new worlds every frame when
|
||||||
// swapping out the Render World.
|
// swapping out the Render World.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -114,7 +118,7 @@ impl Plugin for RenderPlugin {
|
||||||
.init_resource::<RenderGraph>()
|
.init_resource::<RenderGraph>()
|
||||||
.init_resource::<DrawFunctions>();
|
.init_resource::<DrawFunctions>();
|
||||||
|
|
||||||
app.add_sub_app(render_app, move |app_world, render_app| {
|
app.add_sub_app(RenderSubApp, render_app, move |app_world, render_app| {
|
||||||
// reserve all existing app entities for use in render_app
|
// reserve all existing app entities for use in render_app
|
||||||
// they can only be spawned using `get_or_spawn()`
|
// they can only be spawned using `get_or_spawn()`
|
||||||
let meta_len = app_world.entities().meta.len();
|
let meta_len = app_world.entities().meta.len();
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
RenderStage,
|
RenderStage, RenderSubApp,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{Asset, AssetEvent, Assets, Handle};
|
use bevy_asset::{Asset, AssetEvent, Assets, Handle};
|
||||||
|
@ -31,7 +31,7 @@ impl<A: RenderAsset> Default for RenderAssetPlugin<A> {
|
||||||
|
|
||||||
impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> {
|
impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
let render_app = app.sub_app_mut(0);
|
let render_app = app.sub_app_mut(RenderSubApp).unwrap();
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<ExtractedAssets<A>>()
|
.init_resource::<ExtractedAssets<A>>()
|
||||||
.init_resource::<RenderAssets<A>>()
|
.init_resource::<RenderAssets<A>>()
|
||||||
|
|
|
@ -13,7 +13,7 @@ pub use hdr_texture_loader::*;
|
||||||
pub use image_texture_loader::*;
|
pub use image_texture_loader::*;
|
||||||
pub use texture_cache::*;
|
pub use texture_cache::*;
|
||||||
|
|
||||||
use crate::{render_asset::RenderAssetPlugin, RenderStage};
|
use crate::{render_asset::RenderAssetPlugin, RenderStage, RenderSubApp};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::AddAsset;
|
use bevy_asset::AddAsset;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ impl Plugin for ImagePlugin {
|
||||||
app.add_plugin(RenderAssetPlugin::<Image>::default())
|
app.add_plugin(RenderAssetPlugin::<Image>::default())
|
||||||
.add_asset::<Image>();
|
.add_asset::<Image>();
|
||||||
|
|
||||||
let render_app = app.sub_app_mut(0);
|
let render_app = app.sub_app_mut(RenderSubApp).unwrap();
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<TextureCache>()
|
.init_resource::<TextureCache>()
|
||||||
.add_system_to_stage(RenderStage::Cleanup, update_texture_cache_system);
|
.add_system_to_stage(RenderStage::Cleanup, update_texture_cache_system);
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
render_graph::{Node, NodeRunError, RenderGraph, RenderGraphContext},
|
render_graph::{Node, NodeRunError, RenderGraph, RenderGraphContext},
|
||||||
render_resource::DynamicUniformVec,
|
render_resource::DynamicUniformVec,
|
||||||
renderer::{RenderContext, RenderDevice},
|
renderer::{RenderContext, RenderDevice},
|
||||||
RenderStage,
|
RenderStage, RenderSubApp,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
@ -22,7 +22,7 @@ impl ViewPlugin {
|
||||||
|
|
||||||
impl Plugin for ViewPlugin {
|
impl Plugin for ViewPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
let render_app = app.sub_app_mut(0);
|
let render_app = app.sub_app_mut(RenderSubApp).unwrap();
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<ViewMeta>()
|
.init_resource::<ViewMeta>()
|
||||||
.add_system_to_stage(RenderStage::Prepare, prepare_views);
|
.add_system_to_stage(RenderStage::Prepare, prepare_views);
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
render_resource::TextureView,
|
render_resource::TextureView,
|
||||||
renderer::{RenderDevice, RenderInstance},
|
renderer::{RenderDevice, RenderInstance},
|
||||||
texture::BevyDefault,
|
texture::BevyDefault,
|
||||||
RenderStage,
|
RenderStage, RenderSubApp,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
@ -19,7 +19,7 @@ pub struct WindowRenderPlugin;
|
||||||
|
|
||||||
impl Plugin for WindowRenderPlugin {
|
impl Plugin for WindowRenderPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
let render_app = app.sub_app_mut(0);
|
let render_app = app.sub_app_mut(RenderSubApp).unwrap();
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<WindowSurfaces>()
|
.init_resource::<WindowSurfaces>()
|
||||||
.init_resource::<NonSendMarker>()
|
.init_resource::<NonSendMarker>()
|
||||||
|
|
|
@ -16,7 +16,9 @@ pub use texture_atlas::*;
|
||||||
pub use texture_atlas_builder::*;
|
pub use texture_atlas_builder::*;
|
||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
use bevy_render2::{render_graph::RenderGraph, render_phase::DrawFunctions, RenderStage};
|
use bevy_render2::{
|
||||||
|
render_graph::RenderGraph, render_phase::DrawFunctions, RenderStage, RenderSubApp,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SpritePlugin;
|
pub struct SpritePlugin;
|
||||||
|
@ -26,7 +28,7 @@ impl Plugin for SpritePlugin {
|
||||||
app.add_asset::<TextureAtlas>()
|
app.add_asset::<TextureAtlas>()
|
||||||
.register_type::<Sprite>()
|
.register_type::<Sprite>()
|
||||||
.add_system_to_stage(CoreStage::PostUpdate, sprite_auto_resize_system);
|
.add_system_to_stage(CoreStage::PostUpdate, sprite_auto_resize_system);
|
||||||
let render_app = app.sub_app_mut(0);
|
let render_app = app.sub_app_mut(RenderSubApp).unwrap();
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<ExtractedSprites>()
|
.init_resource::<ExtractedSprites>()
|
||||||
.add_system_to_stage(RenderStage::Extract, render::extract_atlases)
|
.add_system_to_stage(RenderStage::Extract, render::extract_atlases)
|
||||||
|
@ -42,7 +44,7 @@ impl Plugin for SpritePlugin {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.write()
|
.write()
|
||||||
.add(draw_sprite);
|
.add(draw_sprite);
|
||||||
let render_world = app.sub_app_mut(0).world.cell();
|
let render_world = app.sub_app_mut(RenderSubApp).unwrap().world.cell();
|
||||||
let mut graph = render_world.get_resource_mut::<RenderGraph>().unwrap();
|
let mut graph = render_world.get_resource_mut::<RenderGraph>().unwrap();
|
||||||
graph.add_node("sprite", SpriteNode);
|
graph.add_node("sprite", SpriteNode);
|
||||||
graph
|
graph
|
||||||
|
|
|
@ -7,6 +7,7 @@ crates=(
|
||||||
bevy_tasks
|
bevy_tasks
|
||||||
bevy_ecs/macros
|
bevy_ecs/macros
|
||||||
bevy_ecs
|
bevy_ecs
|
||||||
|
bevy_app/macros
|
||||||
bevy_app
|
bevy_app
|
||||||
bevy_log
|
bevy_log
|
||||||
bevy_dynamic_plugin
|
bevy_dynamic_plugin
|
||||||
|
@ -42,4 +43,4 @@ do
|
||||||
done
|
done
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
cargo publish
|
cargo publish
|
||||||
|
|
Loading…
Add table
Reference in a new issue