Skip to content

Commit

Permalink
Add bevy_ecs::schedule_v3 module (bevyengine#6587)
Browse files Browse the repository at this point in the history
# Objective

Complete the first part of the migration detailed in bevyengine/rfcs#45.

## Solution

Add all the new stuff.

### TODO

- [x] Impl tuple methods.
- [x] Impl chaining.
- [x] Port ambiguity detection.
- [x] Write docs.
- [x] ~~Write more tests.~~(will do later)
- [ ] Write changelog and examples here?
- [x] ~~Replace `petgraph`.~~ (will do later)



Co-authored-by: james7132 <[email protected]>
Co-authored-by: Michael Hsu <[email protected]>
Co-authored-by: Mike Hsu <[email protected]>
  • Loading branch information
3 people authored and ItsDoot committed Feb 1, 2023
1 parent 5ebda30 commit 9b14b41
Show file tree
Hide file tree
Showing 25 changed files with 4,050 additions and 7 deletions.
30 changes: 29 additions & 1 deletion crates/bevy_ecs/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ mod component;
mod fetch;

use crate::fetch::derive_world_query_impl;
use bevy_macro_utils::{derive_label, get_named_struct_fields, BevyManifest};
use bevy_macro_utils::{
derive_boxed_label, derive_label, derive_set, get_named_struct_fields, BevyManifest,
};
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{format_ident, quote};
Expand Down Expand Up @@ -565,6 +567,32 @@ pub fn derive_run_criteria_label(input: TokenStream) -> TokenStream {
derive_label(input, &trait_path, "run_criteria_label")
}

/// Derive macro generating an impl of the trait `ScheduleLabel`.
#[proc_macro_derive(ScheduleLabel)]
pub fn derive_schedule_label(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let mut trait_path = bevy_ecs_path();
trait_path
.segments
.push(format_ident!("schedule_v3").into());
trait_path
.segments
.push(format_ident!("ScheduleLabel").into());
derive_boxed_label(input, &trait_path)
}

/// Derive macro generating an impl of the trait `SystemSet`.
#[proc_macro_derive(SystemSet)]
pub fn derive_system_set(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let mut trait_path = bevy_ecs_path();
trait_path
.segments
.push(format_ident!("schedule_v3").into());
trait_path.segments.push(format_ident!("SystemSet").into());
derive_set(input, &trait_path)
}

pub(crate) fn bevy_ecs_path() -> syn::Path {
BevyManifest::default().get_path("bevy_ecs")
}
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_ecs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod query;
#[cfg(feature = "bevy_reflect")]
pub mod reflect;
pub mod schedule;
pub mod schedule_v3;
pub mod storage;
pub mod system;
pub mod world;
Expand Down
97 changes: 97 additions & 0 deletions crates/bevy_ecs/src/schedule_v3/condition.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
pub use common_conditions::*;

use crate::system::BoxedSystem;

pub type BoxedCondition = BoxedSystem<(), bool>;

/// A system that determines if one or more scheduled systems should run.
///
/// Implemented for functions and closures that convert into [`System<In=(), Out=bool>`](crate::system::System)
/// with [read-only](crate::system::ReadOnlySystemParam) parameters.
pub trait Condition<Params>: sealed::Condition<Params> {}

impl<Params, F> Condition<Params> for F where F: sealed::Condition<Params> {}

mod sealed {
use crate::system::{IntoSystem, IsFunctionSystem, ReadOnlySystemParam, SystemParamFunction};

pub trait Condition<Params>: IntoSystem<(), bool, Params> {}

impl<Params, Marker, F> Condition<(IsFunctionSystem, Params, Marker)> for F
where
F: SystemParamFunction<(), bool, Params, Marker> + Send + Sync + 'static,
Params: ReadOnlySystemParam + 'static,
Marker: 'static,
{
}
}

mod common_conditions {
use crate::schedule_v3::{State, States};
use crate::system::{Res, Resource};

/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// if the resource exists.
pub fn resource_exists<T>() -> impl FnMut(Option<Res<T>>) -> bool
where
T: Resource,
{
move |res: Option<Res<T>>| res.is_some()
}

/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// if the resource is equal to `value`.
///
/// # Panics
///
/// The condition will panic if the resource does not exist.
pub fn resource_equals<T>(value: T) -> impl FnMut(Res<T>) -> bool
where
T: Resource + PartialEq,
{
move |res: Res<T>| *res == value
}

/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// if the resource exists and is equal to `value`.
///
/// The condition will return `false` if the resource does not exist.
pub fn resource_exists_and_equals<T>(value: T) -> impl FnMut(Option<Res<T>>) -> bool
where
T: Resource + PartialEq,
{
move |res: Option<Res<T>>| match res {
Some(res) => *res == value,
None => false,
}
}

/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// if the state machine exists.
pub fn state_exists<S: States>() -> impl FnMut(Option<Res<State<S>>>) -> bool {
move |current_state: Option<Res<State<S>>>| current_state.is_some()
}

/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// if the state machine is currently in `state`.
///
/// # Panics
///
/// The condition will panic if the resource does not exist.
pub fn state_equals<S: States>(state: S) -> impl FnMut(Res<State<S>>) -> bool {
move |current_state: Res<State<S>>| current_state.0 == state
}

/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// if the state machine exists and is currently in `state`.
///
/// The condition will return `false` if the state does not exist.
pub fn state_exists_and_equals<S: States>(
state: S,
) -> impl FnMut(Option<Res<State<S>>>) -> bool {
move |current_state: Option<Res<State<S>>>| match current_state {
Some(current_state) => current_state.0 == state,
None => false,
}
}
}
Loading

0 comments on commit 9b14b41

Please sign in to comment.