Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

integrate latest changes from Bevy #709

Merged
merged 8 commits into from
Dec 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions lib/app/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt::Debug;

pub use lgn_derive::AppLabel;
use lgn_ecs::{
prelude::{FromWorld, IntoExclusiveSystem},
schedule::{
Expand All @@ -10,10 +11,13 @@ use lgn_ecs::{
world::World,
};
use lgn_telemetry::trace_scope;
use lgn_utils::HashMap;
use log::debug;

use crate::{CoreStage, Events, Plugin, PluginGroup, PluginGroupBuilder, StartupStage};

lgn_utils::define_label!(AppLabel);

#[allow(clippy::needless_doctest_main)]
/// Containers of app logic and data
///
Expand Down Expand Up @@ -42,6 +46,12 @@ pub struct App {
pub world: World,
pub runner: Box<dyn FnOnce(App)>,
pub schedule: Schedule,
sub_apps: HashMap<Box<dyn AppLabel>, SubApp>,
}

struct SubApp {
app: App,
runner: Box<dyn Fn(&mut World, &mut App)>,
}

impl Default for App {
Expand Down Expand Up @@ -70,6 +80,7 @@ impl App {
world: World::default(),
schedule: Schedule::default(),
runner: Box::new(run_once),
sub_apps: HashMap::default(),
}
}

Expand All @@ -79,6 +90,9 @@ impl App {
pub fn update(&mut self) {
trace_scope!("frame");
self.schedule.run(&mut self.world);
for sub_app in self.sub_apps.values_mut() {
(sub_app.runner)(&mut self.world, &mut sub_app.app);
}
}

/// Starts the application by calling the app's [runner function](Self::set_runner).
Expand Down Expand Up @@ -802,6 +816,40 @@ impl App {
plugin_group_builder.finish(self);
self
}

pub fn add_sub_app(
&mut self,
label: impl AppLabel,
app: Self,
f: impl Fn(&mut World, &mut Self) + 'static,
) -> &mut Self {
self.sub_apps.insert(
Box::new(label),
SubApp {
app,
runner: Box::new(f),
},
);
self
}

/// Retrieves a "sub app" stored inside this [App]. This will panic if the sub app does not exist.
pub fn sub_app(&mut self, label: impl AppLabel) -> &mut Self {
match self.get_sub_app(label) {
Ok(app) => app,
Err(label) => panic!("Sub-App with label '{:?}' does not exist", label),
}
}

#[allow(clippy::missing_errors_doc)]
/// Retrieves a "sub app" inside this [App] with the given label, if it exists. Otherwise returns
/// an [Err] containing the given label.
pub fn get_sub_app(&mut self, label: impl AppLabel) -> Result<&mut Self, impl AppLabel> {
self.sub_apps
.get_mut((&label) as &dyn AppLabel)
.map(|sub_app| &mut sub_app.app)
.ok_or(label)
}
}

fn run_once(mut app: App) {
Expand Down
7 changes: 3 additions & 4 deletions lib/app/src/ci_testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,15 @@ fn ci_testing_exit_after(
*current_frame += 1;
}

pub(crate) fn setup_app(app_builder: &mut App) -> &mut App {
pub(crate) fn setup_app(app: &mut App) -> &mut App {
let filename =
std::env::var("CI_TESTING_CONFIG").unwrap_or_else(|_| "ci_testing_config.ron".to_string());
let config: CiTestingConfig = ron::from_str(
&std::fs::read_to_string(filename).expect("error reading CI testing configuration file"),
)
.expect("error deserializing CI testing configuration file");
app_builder
.insert_resource(config)
app.insert_resource(config)
.add_system(ci_testing_exit_after);

app_builder
app
}
6 changes: 4 additions & 2 deletions lib/app/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Legion App
//!
//! TODO: write documentation.
//!
//! This crate is about everything concerning the highest-level, application layer of a Legion
//! app.

// BEGIN - Legion Labs lints v0.6
// do not change or add/remove here, but one can add exceptions after this section
Expand Down Expand Up @@ -82,6 +82,8 @@ pub mod prelude {
use lgn_ecs::schedule::StageLabel;

/// The names of the default App stages
///
/// The relative stages are added by [`App::add_default_stages`].
#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)]
pub enum CoreStage {
/// Runs only once at the beginning of the app.
Expand Down
10 changes: 10 additions & 0 deletions lib/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ mod enum_variant_meta;
mod legion_main;
mod modules;

use lgn_macro_utils::{derive_label, LegionManifest};
use proc_macro::TokenStream;
use quote::format_ident;

/// Derives the Bytes trait. Each field must also implements Bytes or this will fail.
#[proc_macro_derive(Bytes)]
Expand All @@ -88,3 +90,11 @@ pub fn legion_main(attr: TokenStream, item: TokenStream) -> TokenStream {
pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream {
enum_variant_meta::derive_enum_variant_meta(input)
}

#[proc_macro_derive(AppLabel)]
pub fn derive_app_label(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let mut trait_path = LegionManifest::default().get_path(crate::modules::LEGION_APP);
trait_path.segments.push(format_ident!("AppLabel").into());
derive_label(input, trait_path)
}
1 change: 1 addition & 0 deletions lib/derive/src/modules.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub const LEGION_APP: &str = "lgn_app";
pub const LEGION_CORE: &str = "lgn_core";
pub const LEGION_UTILS: &str = "lgn_utils";
2 changes: 1 addition & 1 deletion lib/ecs/macros/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ fn parse_component_attr(ast: &DeriveInput) -> Result<Attrs> {
meta_item.path(),
format!(
"unknown component attribute `{}`",
meta_item.path().into_token_stream().to_string()
meta_item.path().into_token_stream()
),
));
}
Expand Down
54 changes: 25 additions & 29 deletions lib/ecs/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,16 @@

mod component;

use lgn_macro_utils::LegionManifest;
use lgn_macro_utils::{derive_label, LegionManifest};
use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2};
use proc_macro2::Span;
use quote::{format_ident, quote};
use syn::{
parse::{Parse, ParseStream},
parse_macro_input,
punctuated::Punctuated,
token::Comma,
Data, DataStruct, DeriveInput, Field, Fields, GenericParam, Ident, Index, LitInt, Path, Result,
Data, DataStruct, DeriveInput, Field, Fields, GenericParam, Ident, Index, LitInt, Result,
Token,
};

Expand Down Expand Up @@ -489,47 +489,43 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
#[proc_macro_derive(SystemLabel)]
pub fn derive_system_label(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);

derive_label(input, Ident::new("SystemLabel", Span::call_site())).into()
let mut trait_path = legion_ecs_path();
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)]
pub fn derive_stage_label(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
derive_label(input, Ident::new("StageLabel", Span::call_site())).into()
let mut trait_path = legion_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)]
pub fn derive_ambiguity_set_label(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
derive_label(input, Ident::new("AmbiguitySetLabel", Span::call_site())).into()
let mut trait_path = legion_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)]
pub fn derive_run_criteria_label(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
derive_label(input, Ident::new("RunCriteriaLabel", Span::call_site())).into()
}

#[allow(clippy::needless_pass_by_value)]
fn derive_label(input: DeriveInput, label_type: Ident) -> TokenStream2 {
let ident = input.ident;
let ecs_path: Path = legion_ecs_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: syn::token::Where::default(),
predicates: Punctuated::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))
}
}
}
let mut trait_path = legion_ecs_path();
trait_path.segments.push(format_ident!("schedule").into());
trait_path
.segments
.push(format_ident!("RunCriteriaLabel").into());
derive_label(input, trait_path)
}

fn legion_ecs_path() -> syn::Path {
Expand Down
2 changes: 1 addition & 1 deletion lib/ecs/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub struct TableStorage;
pub struct SparseStorage;

pub trait ComponentStorage: sealed::Sealed {
// because the trait is selaed, those items are private API.
// because the trait is sealed, those items are private API.
const STORAGE_TYPE: StorageType;
}

Expand Down
25 changes: 25 additions & 0 deletions lib/ecs/src/entity/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
//! Entity handling types.
//!
//! In Legion ECS, there is no monolithic data structure for an entity. Instead, the [`Entity`]
//! `struct` is just a *generational index* (a combination of an ID and a generation). Then,
//! the `Entity` maps to the specific [`Component`s](crate::component::Component). This way,
//! entities can have meaningful data attached to it. This is a fundamental design choice
//! that has been taken to enhance performance and usability.
//!
//! # Usage
//!
//! Here are links to the methods used to perform common operations
//! involving entities:
//!
//! - **Spawning an empty entity:** use [`Commands::spawn`](crate::system::Commands::spawn).
//! - **Spawning an entity with components:** use
//! [`Commands::spawn_bundle`](crate::system::Commands::spawn_bundle).
//! - **Despawning an entity:** use
//! [`EntityCommands::despawn`](crate::system::EntityCommands::despawn).
//! - **Inserting a component to an entity:** use
//! [`EntityCommands::insert`](crate::system::EntityCommands::insert).
//! - **Adding multiple components to an entity:** use
//! [`EntityCommands::insert_bundle`](crate::system::EntityCommands::insert_bundle).
//! - **Removing a component to an entity:** use
//! [`EntityCommands::remove`](crate::system::EntityCommands::remove).

#![allow(unsafe_code)]

mod map_entities;
Expand Down
2 changes: 2 additions & 0 deletions lib/ecs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ pub mod prelude {
};
}

pub use lgn_ecs_macros::all_tuples;

#[cfg(test)]
mod tests {
use std::{
Expand Down
12 changes: 12 additions & 0 deletions lib/ecs/src/query/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ impl<T: SparseSetIndex> Access<T> {
.map(SparseSetIndex::get_sparse_set_index)
.collect()
}

/// Returns all read accesses.
pub fn reads(&self) -> impl Iterator<Item = T> + '_ {
self.reads_and_writes
.difference(&self.writes)
.map(T::get_sparse_set_index)
}

/// Returns all write accesses.
pub fn writes(&self) -> impl Iterator<Item = T> + '_ {
self.writes.ones().map(T::get_sparse_set_index)
}
}

#[derive(Clone, Eq, PartialEq)]
Expand Down
Loading