Skip to content

Commit

Permalink
Add Missing Features To the Dynamicsystem API
Browse files Browse the repository at this point in the history
Added features such as init_function, thread_local_system, local state,
and multiple queries to the DynamicSystem API. Also changed the
DynamicSystem initializer to be more convenient with the variety of
options.
  • Loading branch information
zicklag committed Oct 19, 2020
1 parent 4544790 commit a362d2e
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 73 deletions.
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub mod prelude {
pub use crate::{
resource::{ChangedRes, FromResources, Local, OrRes, Res, ResMut, Resource, Resources},
system::{
Commands, DynamicSystem, DynamicSystemWorkload, IntoForEachSystem, IntoQuerySystem,
Commands, DynamicSystem, DynamicSystemSettings, IntoForEachSystem, IntoQuerySystem,
IntoThreadLocalSystem, Query, System,
},
world::WorldBuilderSource,
Expand Down
95 changes: 59 additions & 36 deletions crates/bevy_ecs/src/system/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,38 +118,58 @@ impl TypeAccess {
}
}

pub type DynamicSystemWorkload =
fn(&mut GenericQuery<DynamicComponentQuery, DynamicComponentQuery>);

pub struct DynamicSystem {
name: String,
pub struct DynamicSystem<S> {
pub name: String,
pub state: S,
system_id: SystemId,
workload: DynamicSystemWorkload,
archetype_access: ArchetypeAccess,
resource_access: TypeAccess,
component_query: DynamicComponentQuery,
settings: DynamicSystemSettings<S>,
}

#[derive(Clone)]
pub struct DynamicSystemSettings<S> {
pub workload:
fn(&mut S, &Resources, &mut [GenericQuery<DynamicComponentQuery, DynamicComponentQuery>]),
pub queries: Vec<DynamicComponentQuery>,
pub thread_local_execution: ThreadLocalExecution,
pub thread_local_system: fn(&mut S, &mut World, &mut Resources),
pub init_function: fn(&mut S, &mut World, &mut Resources),
pub resource_access: TypeAccess,
}

impl<S> Default for DynamicSystemSettings<S> {
fn default() -> Self {
Self {
workload: |_, _, _| (),
queries: Default::default(),
thread_local_execution: ThreadLocalExecution::NextFlush,
thread_local_system: |_, _, _| (),
init_function: |_, _, _| (),
resource_access: Default::default(),
}
}
}

impl DynamicSystem {
pub fn new(
name: String,
component_query: DynamicComponentQuery,
workload: DynamicSystemWorkload,
) -> Self {
impl<S> DynamicSystem<S> {
pub fn new(name: String, state: S) -> Self {
DynamicSystem {
name,
workload,
component_query,
state,
system_id: SystemId::new(),
resource_access: Default::default(),
archetype_access: Default::default(),
system_id: SystemId::new(),
settings: Default::default(),
}
}

// TODO: Impl `Default` for `DynamicSystem`
pub fn settings(mut self, settings: DynamicSystemSettings<S>) -> Self {
self.settings = settings;
self
}
}

impl System for DynamicSystem {
impl<S: Send + Sync> System for DynamicSystem<S> {
fn name(&self) -> std::borrow::Cow<'static, str> {
self.name.clone().into()
}
Expand All @@ -162,40 +182,43 @@ impl System for DynamicSystem {
// Clear previous archetype access list
self.archetype_access.clear();

self.archetype_access
.set_access_for_stateful_query::<_, DynamicComponentQuery>(
&world,
&self.component_query,
);
for query in &self.settings.queries {
self.archetype_access
.set_access_for_stateful_query::<_, DynamicComponentQuery>(&world, &query);
}
}

fn archetype_access(&self) -> &ArchetypeAccess {
&self.archetype_access
}

// TODO: Allow specifying resource access
fn resource_access(&self) -> &TypeAccess {
&self.resource_access
}

// TODO: Allow specifying the thread local execution
fn thread_local_execution(&self) -> ThreadLocalExecution {
ThreadLocalExecution::NextFlush
self.settings.thread_local_execution
}

fn run(&mut self, world: &World, _resources: &Resources) {
(self.workload)(&mut GenericQuery::new_stateful(
world,
&self.archetype_access,
&self.component_query,
));
fn run(&mut self, world: &World, resources: &Resources) {
let archetype_access = &self.archetype_access;
let mut queries: Vec<_> = self
.settings
.queries
.iter()
.map(|query| GenericQuery::new_stateful(world, &archetype_access, query))
.collect();

(self.settings.workload)(&mut self.state, resources, queries.as_mut_slice());
}

// TODO: Allow specifying a thread local system
fn run_thread_local(&mut self, _world: &mut World, _resources: &mut Resources) {}
fn run_thread_local(&mut self, world: &mut World, resources: &mut Resources) {
(self.settings.thread_local_system)(&mut self.state, world, resources);
}

// TODO: Allow specifying an initialization function
fn initialize(&mut self, _world: &mut World, _resources: &mut Resources) {}
fn initialize(&mut self, world: &mut World, resources: &mut Resources) {
(self.settings.init_function)(&mut self.state, world, resources);
}
}

#[cfg(test)]
Expand Down
79 changes: 43 additions & 36 deletions examples/ecs/dynamic_systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::time::Duration;

use bevy::prelude::*;
use bevy_app::ScheduleRunnerPlugin;
use bevy_ecs::{ComponentId, DynamicComponentInfo, DynamicComponentQuery};
use bevy_ecs::{ComponentId, DynamicComponentInfo, DynamicComponentQuery, DynamicSystemSettings};

// Define our componens

Expand Down Expand Up @@ -91,41 +91,48 @@ fn main() {

// Create our dynamic system by specifying the name, the query we created above, and a closure
// that operates on the query
let pos_vel_system = DynamicSystem::new("pos_vel_system".into(), query, |query| {
// Iterate over the query just like you would in a typical query
for mut components in &mut query.iter() {
// `components` will be an array with indexes corresponding to the indexes of our
// DynamicComponentAccess information that we constructed for our query when creating
// the system.
//
// Each item in the array is an optional mutable reference to a byte slice representing
// the component data: Option<&mut [u8]>.

// Here we take the mutable reference to the bytes of our position and velocity
// components
let pos_bytes = components.mutable[0].take().unwrap();
let vel_bytes = components.immutable[0].take().unwrap();

unsafe fn from_slice_mut<T>(s: &mut [u8]) -> &mut T {
debug_assert_eq!(std::mem::size_of::<T>(), s.len());
&mut *(s.as_mut_ptr() as *mut T)
}

unsafe fn from_slice<T>(s: &[u8]) -> &T {
debug_assert_eq!(std::mem::size_of::<T>(), s.len());
&*(s.as_ptr() as *mut T)
}

// Instead of interacting with the raw bytes of our components, we first cast them to
// their Rust structs
let mut pos: &mut Pos = unsafe { from_slice_mut(pos_bytes) };
let vel: &Vel = unsafe { from_slice(vel_bytes) };

// Now we can operate on our components
pos.x += vel.x;
pos.y += vel.y;
}
});
let pos_vel_system =
DynamicSystem::new("pos_vel_system".into(), () /* system local state */).settings(
DynamicSystemSettings {
queries: vec![query],
workload: |_state, _resources, queries| {
// Iterate over the query just like you would in a typical query
for mut components in &mut queries[0].iter() {
// `components` will be an array with indexes corresponding to the indexes of our
// DynamicComponentAccess information that we constructed for our query when creating
// the system.
//
// Each item in the array is an optional mutable reference to a byte slice representing
// the component data: Option<&mut [u8]>.

// Here we take the mutable reference to the bytes of our position and velocity
// components
let pos_bytes = components.mutable[0].take().unwrap();
let vel_bytes = components.immutable[0].take().unwrap();

unsafe fn from_slice_mut<T>(s: &mut [u8]) -> &mut T {
debug_assert_eq!(std::mem::size_of::<T>(), s.len());
&mut *(s.as_mut_ptr() as *mut T)
}

unsafe fn from_slice<T>(s: &[u8]) -> &T {
debug_assert_eq!(std::mem::size_of::<T>(), s.len());
&*(s.as_ptr() as *mut T)
}

// Instead of interacting with the raw bytes of our components, we first cast them to
// their Rust structs
let mut pos: &mut Pos = unsafe { from_slice_mut(pos_bytes) };
let vel: &Vel = unsafe { from_slice(vel_bytes) };

// Now we can operate on our components
pos.x += vel.x;
pos.y += vel.y;
}
},
..Default::default()
},
);

App::build()
.add_plugin(ScheduleRunnerPlugin::run_loop(Duration::from_secs(1)))
Expand Down

0 comments on commit a362d2e

Please sign in to comment.