Skip to content

Commit a362d2e

Browse files
committed
Add Missing Features To the Dynamicsystem API
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.
1 parent 4544790 commit a362d2e

File tree

3 files changed

+103
-73
lines changed

3 files changed

+103
-73
lines changed

crates/bevy_ecs/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub mod prelude {
1313
pub use crate::{
1414
resource::{ChangedRes, FromResources, Local, OrRes, Res, ResMut, Resource, Resources},
1515
system::{
16-
Commands, DynamicSystem, DynamicSystemWorkload, IntoForEachSystem, IntoQuerySystem,
16+
Commands, DynamicSystem, DynamicSystemSettings, IntoForEachSystem, IntoQuerySystem,
1717
IntoThreadLocalSystem, Query, System,
1818
},
1919
world::WorldBuilderSource,

crates/bevy_ecs/src/system/system.rs

+59-36
Original file line numberDiff line numberDiff line change
@@ -118,38 +118,58 @@ impl TypeAccess {
118118
}
119119
}
120120

121-
pub type DynamicSystemWorkload =
122-
fn(&mut GenericQuery<DynamicComponentQuery, DynamicComponentQuery>);
123-
124-
pub struct DynamicSystem {
125-
name: String,
121+
pub struct DynamicSystem<S> {
122+
pub name: String,
123+
pub state: S,
126124
system_id: SystemId,
127-
workload: DynamicSystemWorkload,
128125
archetype_access: ArchetypeAccess,
129126
resource_access: TypeAccess,
130-
component_query: DynamicComponentQuery,
127+
settings: DynamicSystemSettings<S>,
128+
}
129+
130+
#[derive(Clone)]
131+
pub struct DynamicSystemSettings<S> {
132+
pub workload:
133+
fn(&mut S, &Resources, &mut [GenericQuery<DynamicComponentQuery, DynamicComponentQuery>]),
134+
pub queries: Vec<DynamicComponentQuery>,
135+
pub thread_local_execution: ThreadLocalExecution,
136+
pub thread_local_system: fn(&mut S, &mut World, &mut Resources),
137+
pub init_function: fn(&mut S, &mut World, &mut Resources),
138+
pub resource_access: TypeAccess,
139+
}
140+
141+
impl<S> Default for DynamicSystemSettings<S> {
142+
fn default() -> Self {
143+
Self {
144+
workload: |_, _, _| (),
145+
queries: Default::default(),
146+
thread_local_execution: ThreadLocalExecution::NextFlush,
147+
thread_local_system: |_, _, _| (),
148+
init_function: |_, _, _| (),
149+
resource_access: Default::default(),
150+
}
151+
}
131152
}
132153

133-
impl DynamicSystem {
134-
pub fn new(
135-
name: String,
136-
component_query: DynamicComponentQuery,
137-
workload: DynamicSystemWorkload,
138-
) -> Self {
154+
impl<S> DynamicSystem<S> {
155+
pub fn new(name: String, state: S) -> Self {
139156
DynamicSystem {
140157
name,
141-
workload,
142-
component_query,
158+
state,
159+
system_id: SystemId::new(),
143160
resource_access: Default::default(),
144161
archetype_access: Default::default(),
145-
system_id: SystemId::new(),
162+
settings: Default::default(),
146163
}
147164
}
148165

149-
// TODO: Impl `Default` for `DynamicSystem`
166+
pub fn settings(mut self, settings: DynamicSystemSettings<S>) -> Self {
167+
self.settings = settings;
168+
self
169+
}
150170
}
151171

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

165-
self.archetype_access
166-
.set_access_for_stateful_query::<_, DynamicComponentQuery>(
167-
&world,
168-
&self.component_query,
169-
);
185+
for query in &self.settings.queries {
186+
self.archetype_access
187+
.set_access_for_stateful_query::<_, DynamicComponentQuery>(&world, &query);
188+
}
170189
}
171190

172191
fn archetype_access(&self) -> &ArchetypeAccess {
173192
&self.archetype_access
174193
}
175194

176-
// TODO: Allow specifying resource access
177195
fn resource_access(&self) -> &TypeAccess {
178196
&self.resource_access
179197
}
180198

181-
// TODO: Allow specifying the thread local execution
182199
fn thread_local_execution(&self) -> ThreadLocalExecution {
183-
ThreadLocalExecution::NextFlush
200+
self.settings.thread_local_execution
184201
}
185202

186-
fn run(&mut self, world: &World, _resources: &Resources) {
187-
(self.workload)(&mut GenericQuery::new_stateful(
188-
world,
189-
&self.archetype_access,
190-
&self.component_query,
191-
));
203+
fn run(&mut self, world: &World, resources: &Resources) {
204+
let archetype_access = &self.archetype_access;
205+
let mut queries: Vec<_> = self
206+
.settings
207+
.queries
208+
.iter()
209+
.map(|query| GenericQuery::new_stateful(world, &archetype_access, query))
210+
.collect();
211+
212+
(self.settings.workload)(&mut self.state, resources, queries.as_mut_slice());
192213
}
193214

194-
// TODO: Allow specifying a thread local system
195-
fn run_thread_local(&mut self, _world: &mut World, _resources: &mut Resources) {}
215+
fn run_thread_local(&mut self, world: &mut World, resources: &mut Resources) {
216+
(self.settings.thread_local_system)(&mut self.state, world, resources);
217+
}
196218

197-
// TODO: Allow specifying an initialization function
198-
fn initialize(&mut self, _world: &mut World, _resources: &mut Resources) {}
219+
fn initialize(&mut self, world: &mut World, resources: &mut Resources) {
220+
(self.settings.init_function)(&mut self.state, world, resources);
221+
}
199222
}
200223

201224
#[cfg(test)]

examples/ecs/dynamic_systems.rs

+43-36
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::time::Duration;
1010

1111
use bevy::prelude::*;
1212
use bevy_app::ScheduleRunnerPlugin;
13-
use bevy_ecs::{ComponentId, DynamicComponentInfo, DynamicComponentQuery};
13+
use bevy_ecs::{ComponentId, DynamicComponentInfo, DynamicComponentQuery, DynamicSystemSettings};
1414

1515
// Define our componens
1616

@@ -91,41 +91,48 @@ fn main() {
9191

9292
// Create our dynamic system by specifying the name, the query we created above, and a closure
9393
// that operates on the query
94-
let pos_vel_system = DynamicSystem::new("pos_vel_system".into(), query, |query| {
95-
// Iterate over the query just like you would in a typical query
96-
for mut components in &mut query.iter() {
97-
// `components` will be an array with indexes corresponding to the indexes of our
98-
// DynamicComponentAccess information that we constructed for our query when creating
99-
// the system.
100-
//
101-
// Each item in the array is an optional mutable reference to a byte slice representing
102-
// the component data: Option<&mut [u8]>.
103-
104-
// Here we take the mutable reference to the bytes of our position and velocity
105-
// components
106-
let pos_bytes = components.mutable[0].take().unwrap();
107-
let vel_bytes = components.immutable[0].take().unwrap();
108-
109-
unsafe fn from_slice_mut<T>(s: &mut [u8]) -> &mut T {
110-
debug_assert_eq!(std::mem::size_of::<T>(), s.len());
111-
&mut *(s.as_mut_ptr() as *mut T)
112-
}
113-
114-
unsafe fn from_slice<T>(s: &[u8]) -> &T {
115-
debug_assert_eq!(std::mem::size_of::<T>(), s.len());
116-
&*(s.as_ptr() as *mut T)
117-
}
118-
119-
// Instead of interacting with the raw bytes of our components, we first cast them to
120-
// their Rust structs
121-
let mut pos: &mut Pos = unsafe { from_slice_mut(pos_bytes) };
122-
let vel: &Vel = unsafe { from_slice(vel_bytes) };
123-
124-
// Now we can operate on our components
125-
pos.x += vel.x;
126-
pos.y += vel.y;
127-
}
128-
});
94+
let pos_vel_system =
95+
DynamicSystem::new("pos_vel_system".into(), () /* system local state */).settings(
96+
DynamicSystemSettings {
97+
queries: vec![query],
98+
workload: |_state, _resources, queries| {
99+
// Iterate over the query just like you would in a typical query
100+
for mut components in &mut queries[0].iter() {
101+
// `components` will be an array with indexes corresponding to the indexes of our
102+
// DynamicComponentAccess information that we constructed for our query when creating
103+
// the system.
104+
//
105+
// Each item in the array is an optional mutable reference to a byte slice representing
106+
// the component data: Option<&mut [u8]>.
107+
108+
// Here we take the mutable reference to the bytes of our position and velocity
109+
// components
110+
let pos_bytes = components.mutable[0].take().unwrap();
111+
let vel_bytes = components.immutable[0].take().unwrap();
112+
113+
unsafe fn from_slice_mut<T>(s: &mut [u8]) -> &mut T {
114+
debug_assert_eq!(std::mem::size_of::<T>(), s.len());
115+
&mut *(s.as_mut_ptr() as *mut T)
116+
}
117+
118+
unsafe fn from_slice<T>(s: &[u8]) -> &T {
119+
debug_assert_eq!(std::mem::size_of::<T>(), s.len());
120+
&*(s.as_ptr() as *mut T)
121+
}
122+
123+
// Instead of interacting with the raw bytes of our components, we first cast them to
124+
// their Rust structs
125+
let mut pos: &mut Pos = unsafe { from_slice_mut(pos_bytes) };
126+
let vel: &Vel = unsafe { from_slice(vel_bytes) };
127+
128+
// Now we can operate on our components
129+
pos.x += vel.x;
130+
pos.y += vel.y;
131+
}
132+
},
133+
..Default::default()
134+
},
135+
);
129136

130137
App::build()
131138
.add_plugin(ScheduleRunnerPlugin::run_loop(Duration::from_secs(1)))

0 commit comments

Comments
 (0)