use amethyst_core::{
deferred_dispatcher_operation::*,
ecs::{DispatcherBuilder, System, SystemData, World},
SystemBundle, SystemDesc,
};
use amethyst_error::Error;
use log::info;
use crate::{
objects::PhysicsSetupStorages,
systems::{
PhysicsAttachmentSystem, PhysicsBatchSystem, PhysicsStepperSystem, PhysicsSyncEntitySystem,
PhysicsSyncJointSystem, PhysicsSyncShapeSystem, PhysicsSyncTransformFromSystem,
PhysicsSyncTransformToSystem,
},
PhysicsTime,
};
#[allow(missing_debug_implementations)]
pub struct PhysicsBundle<'a, 'b, N: crate::PtReal, B: crate::PhysicsBackend<N>> {
phantom_data_float: std::marker::PhantomData<N>,
phantom_data_backend: std::marker::PhantomData<B>,
physics_time: PhysicsTime,
physics_builder: DispatcherBuilder<'a, 'b>,
pre_physics_dispatcher_operations: Vec<Box<dyn DispatcherOperation<'a, 'b>>>,
in_physics_dispatcher_operations: Vec<Box<dyn DispatcherOperation<'a, 'b>>>,
post_physics_dispatcher_operations: Vec<Box<dyn DispatcherOperation<'a, 'b>>>,
}
macro_rules! define_setters{
($(#[$doc_sy:meta])* $with_system:ident, $add_system:ident, $(#[$doc_sd:meta])* $with_system_desc:ident, $add_system_desc:ident, $(#[$doc_bund:meta])* $with_bundle:ident, $add_bundle:ident, $(#[$doc_bar:meta])* $with_barrier:ident, $add_barrier:ident, $vec:ident) => {
$(#[$doc_sy])*
pub fn $with_system<S>(
mut self,
system: S,
name: String,
dependencies: Vec<String>,
) -> Self
where
S: for<'c> System<'c> + 'static + Send,
{
self.$add_system(system, name, dependencies);
self
}
$(#[$doc_sy])*
pub fn $add_system<S>(
&mut self,
system: S,
name: String,
dependencies: Vec<String>,
) where
S: for<'c> System<'c> + 'static + Send,
{
self.$vec
.push(Box::new(AddSystem {
system,
name,
dependencies,
}) as Box<dyn DispatcherOperation<'a, 'b>>);
}
$(#[$doc_sd])*
pub fn $with_system_desc<SD, S>(
mut self,
system_desc: SD,
name: String,
dependencies: Vec<String>,
) -> Self
where
SD: SystemDesc<'a, 'b, S> + 'static,
S: for<'s> System<'s> + 'static + Send,
{
self.$add_system_desc(system_desc, name, dependencies);
self
}
$(#[$doc_sd])*
pub fn $add_system_desc<SD, S>(
&mut self,
system_desc: SD,
name: String,
dependencies: Vec<String>,
) where
SD: SystemDesc<'a, 'b, S> + 'static,
S: for<'s> System<'s> + 'static + Send,
{
self.$vec
.push(Box::new(AddSystemDesc::<SD, S>{
system_desc,
name,
dependencies,
marker: std::marker::PhantomData::<S>,
}) as Box<dyn DispatcherOperation<'a, 'b>>);
}
$(#[$doc_bund])*
pub fn $with_bundle<BUND>(
mut self,
bundle: BUND,
) -> Self
where
BUND: SystemBundle<'a, 'b> + 'static + Send,
{
self.$add_bundle(bundle);
self
}
$(#[$doc_bund])*
pub fn $add_bundle<BUND>(
&mut self,
bundle: BUND,
) where
BUND: SystemBundle<'a, 'b> + 'static + Send,
{
self.$vec
.push(Box::new(AddBundle {
bundle,
}) as Box<dyn DispatcherOperation<'a, 'b>>);
}
$(#[$doc_bar])*
pub fn $with_barrier(
mut self,
) -> Self {
self.$add_barrier();
self
}
$(#[$doc_bar])*
pub fn $add_barrier(
&mut self,
){
self.$vec
.push(Box::new(AddBarrier {}) as Box<dyn DispatcherOperation<'a, 'b>>);
}
}
}
impl<'a, 'b, N: crate::PtReal, B: crate::PhysicsBackend<N>> Default
for PhysicsBundle<'a, 'b, N, B>
{
fn default() -> Self {
Self::new()
}
}
impl<'a, 'b, N: crate::PtReal, B: crate::PhysicsBackend<N>> PhysicsBundle<'a, 'b, N, B> {
pub fn new() -> Self {
Self {
phantom_data_float: std::marker::PhantomData,
phantom_data_backend: std::marker::PhantomData,
physics_time: PhysicsTime::default(),
physics_builder: DispatcherBuilder::new(),
pre_physics_dispatcher_operations: Vec::new(),
in_physics_dispatcher_operations: Vec::new(),
post_physics_dispatcher_operations: Vec::new(),
}
}
pub fn with_frames_per_seconds(mut self, frames_per_seconds: u32) -> Self {
self.physics_time.set_frames_per_seconds(frames_per_seconds);
self
}
pub fn set_frames_per_seconds(mut self, frames_per_seconds: u32) {
self.physics_time.set_frames_per_seconds(frames_per_seconds);
}
pub fn with_max_sub_steps(mut self, max_sub_steps: u32) -> Self {
self.physics_time.set_max_sub_steps(max_sub_steps);
self
}
pub fn set_max_sub_steps(mut self, max_sub_steps: u32) {
self.physics_time.set_max_sub_steps(max_sub_steps);
}
define_setters!(
with_pre_physics,
add_pre_physics,
with_system_desc_pre_physics,
add_system_desc_pre_physics,
with_bundle_pre_physics,
add_bundle_pre_physics,
with_barrier_pre_physics,
add_barrier_pre_physics,
pre_physics_dispatcher_operations
);
define_setters!(
with_in_physics,
add_in_physics,
with_system_desc_in_physics,
add_system_desc_in_physics,
with_bundle_in_physics,
add_bundle_in_physics,
with_barrier_in_physics,
add_barrier_in_physics,
in_physics_dispatcher_operations
);
define_setters!(
with_post_physics,
add_post_physics,
with_system_desc_post_physics,
add_system_desc_post_physics,
with_bundle_post_physics,
add_bundle_post_physics,
with_barrier_post_physics,
add_barrier_post_physics,
post_physics_dispatcher_operations
);
}
impl<N, B> SystemBundle<'static, 'static> for PhysicsBundle<'static, 'static, N, B>
where
N: crate::PtReal,
B: crate::PhysicsBackend<N> + Send + 'static,
{
fn build(
self,
world: &mut World,
builder: &mut DispatcherBuilder<'static, 'static>,
) -> Result<(), Error> {
PhysicsSetupStorages::setup(world);
world.insert(B::create_world());
world.insert(self.physics_time);
let physics_builder = {
let mut physics_builder = self.physics_builder;
physics_builder.add(
PhysicsAttachmentSystem::default(),
"physics_attachment",
&[],
);
self.pre_physics_dispatcher_operations
.into_iter()
.try_for_each(|operation| operation.exec(world, &mut physics_builder))
.unwrap_or_else(|e| {
panic!("Failed to setup the pre physics systems. Error: {}", e)
});
physics_builder.add_barrier();
physics_builder.add(PhysicsStepperSystem::<N>::new(), "", &[]);
self.in_physics_dispatcher_operations
.into_iter()
.try_for_each(|operation| operation.exec(world, &mut physics_builder))
.unwrap_or_else(|e| panic!("Failed to setup the in physics systems. Error: {}", e));
physics_builder.add_barrier();
self.post_physics_dispatcher_operations
.into_iter()
.try_for_each(|operation| operation.exec(world, &mut physics_builder))
.unwrap_or_else(|e| {
panic!("Failed to setup the post physics systems. Error: {}", e)
});
physics_builder
};
builder.add(
PhysicsSyncEntitySystem::<N>::default(),
"physics_sync_entity",
&[],
);
builder.add(
PhysicsSyncShapeSystem::<N>::default(),
"physics_sync_shape",
&[],
);
builder.add(
PhysicsSyncTransformToSystem::<N>::new(),
"physics_sync_transform_to",
&[],
);
builder.add(
PhysicsAttachmentSystem::default(), "physics_attachment",
&["physics_sync_transform_to"],
);
builder.add(
PhysicsSyncTransformFromSystem::<N>::new(),
"physics_sync_transform_from",
&["physics_sync_transform_to"],
);
builder.add(
PhysicsSyncJointSystem::<N>::default(),
"physics_sync_joint",
&["physics_attachment"],
);
builder.add_batch::<PhysicsBatchSystem<'static, 'static, N>>(
physics_builder,
"physics_batch",
&[
"physics_sync_shape",
"physics_sync_joint",
"physics_sync_entity",
"physics_sync_transform_to",
"physics_sync_transform_from",
"physics_attachment",
],
);
info!("Physics bundle registered.");
Ok(())
}
}