Skip to content

Commit

Permalink
Implemented SystemDesc builder for examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
azriel91 committed Aug 1, 2019
1 parent a4f1f92 commit 97d3d4f
Show file tree
Hide file tree
Showing 49 changed files with 376 additions and 221 deletions.
8 changes: 4 additions & 4 deletions examples/animation/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
use amethyst::{
animation::*,
assets::{Loader, PrefabLoader, PrefabLoaderSystem, RonFormat},
core::{Transform, TransformBundle},
assets::{Loader, PrefabLoader, PrefabLoaderSystemDesc, RonFormat},
core::{SystemDesc, Transform, TransformBundle},
ecs::prelude::{Entity, World, WorldExt},
input::{get_key, is_close_requested, is_key_down},
prelude::*,
Expand Down Expand Up @@ -223,10 +223,10 @@ fn main() -> amethyst::Result<()> {
let display_config_path = app_root.join("examples/animation/config/display.ron");
let assets_dir = app_root.join("examples/assets/");

let mut world = World::with_application_resources::<GameData<'_, '_>, _>(assets_dir)?;
let world = World::with_application_resources::<GameData<'_, '_>, _>(assets_dir)?;

let game_data = GameDataBuilder::default()
.with(PrefabLoaderSystem::<MyPrefabData>::new(&mut world), "", &[])
.with(PrefabLoaderSystemDesc::<MyPrefabData>::default(), "", &[])
.with_bundle(
RenderingBundle::<DefaultBackend>::new()
.with_plugin(
Expand Down
32 changes: 22 additions & 10 deletions examples/arc_ball_camera/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//! Demonstrates how to use the fly camera
use amethyst::{
assets::{PrefabLoader, PrefabLoaderSystem, RonFormat},
assets::{PrefabLoader, PrefabLoaderSystemDesc, RonFormat},
controls::{ArcBallControlBundle, ArcBallControlTag},
core::{
shrev::{EventChannel, ReaderId},
transform::{Transform, TransformBundle},
SystemDesc,
},
ecs::prelude::{Join, Read, ReadStorage, System, SystemData, World, WorldExt, WriteStorage},
input::{
Expand Down Expand Up @@ -52,17 +53,28 @@ impl SimpleState for ExampleState {
}
}

struct CameraDistanceSystem {
event_reader: ReaderId<InputEvent<StringBindings>>,
}
/// Builds a `CameraDistanceSystem`.
#[derive(Default, Debug)]
pub struct CameraDistanceSystemDesc;

impl<'a, 'b> SystemDesc<'a, 'b, CameraDistanceSystem> for CameraDistanceSystemDesc {
fn build(self, world: &mut World) -> CameraDistanceSystem {
<CameraDistanceSystem as System<'_>>::SystemData::setup(world);

impl CameraDistanceSystem {
pub fn new(mut world: &mut World) -> Self {
<Self as System<'_>>::SystemData::setup(&mut world);
let event_reader = world
.fetch_mut::<EventChannel<InputEvent<StringBindings>>>()
.register_reader();

CameraDistanceSystem::new(event_reader)
}
}

struct CameraDistanceSystem {
event_reader: ReaderId<InputEvent<StringBindings>>,
}

impl CameraDistanceSystem {
pub fn new(event_reader: ReaderId<InputEvent<StringBindings>>) -> Self {
CameraDistanceSystem { event_reader }
}
}
Expand Down Expand Up @@ -105,10 +117,10 @@ fn main() -> Result<(), Error> {

let key_bindings_path = app_root.join("examples/arc_ball_camera/config/input.ron");

let mut world = World::with_application_resources::<GameData<'_, '_>, _>(assets_dir)?;
let world = World::with_application_resources::<GameData<'_, '_>, _>(assets_dir)?;

let game_data = GameDataBuilder::default()
.with(PrefabLoaderSystem::<MyPrefabData>::new(&mut world), "", &[])
.with(PrefabLoaderSystemDesc::<MyPrefabData>::default(), "", &[])
.with_bundle(
RenderingBundle::<DefaultBackend>::new()
.with_plugin(RenderToWindow::from_config_path(display_config_path))
Expand All @@ -124,7 +136,7 @@ fn main() -> Result<(), Error> {
)?
.with_bundle(ArcBallControlBundle::<StringBindings>::new())?
.with(
CameraDistanceSystem::new(&mut world),
CameraDistanceSystemDesc::default(),
"camera_distance_system",
&["input_system"],
);
Expand Down
2 changes: 1 addition & 1 deletion examples/asset_loading/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ fn main() -> Result<(), Error> {

let display_config_path = app_root.join("examples/asset_loading/config/display.ron");

let mut world = World::with_application_resources::<GameData<'_, '_>, _>(assets_dir)?;
let world = World::with_application_resources::<GameData<'_, '_>, _>(assets_dir)?;

let game_data = GameDataBuilder::default()
.with_bundle(
Expand Down
23 changes: 11 additions & 12 deletions examples/auto_fov/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use amethyst::{
assets::{
Completion, Handle, Prefab, PrefabData, PrefabLoader, PrefabLoaderSystem, ProgressCounter,
RonFormat,
Completion, Handle, Prefab, PrefabData, PrefabLoader, PrefabLoaderSystemDesc,
ProgressCounter, RonFormat,
},
core::{Transform, TransformBundle},
derive::PrefabData,
ecs::{Entity, ReadExpect, ReadStorage, System, World, WorldExt, WriteStorage},
core::{SystemDesc, Transform, TransformBundle},
derive::{PrefabData, SystemDesc},
ecs::{Entity, ReadExpect, ReadStorage, System, SystemData, World, WorldExt, WriteStorage},
input::{is_close_requested, is_key_down, InputBundle, StringBindings},
prelude::{
AmethystWorldExt, Application, Builder, GameData, GameDataBuilder, SimpleState,
Expand Down Expand Up @@ -41,18 +41,18 @@ fn main() -> Result<(), Error> {
let display_config_path = app_dir.join("auto_fov/config/display.ron");
let assets_dir = app_dir.join("assets");

let mut world = World::with_application_resources::<GameData<'_, '_>, _>(assets_dir)?;
let world = World::with_application_resources::<GameData<'_, '_>, _>(assets_dir)?;

let game_data = GameDataBuilder::new()
.with(
PrefabLoaderSystem::<ScenePrefab>::new(&mut world),
PrefabLoaderSystemDesc::<ScenePrefab>::default(),
"prefab",
&[],
)
// This makes the system adjust the camera right after it has been loaded (in the same
// frame), preventing any flickering
.with(AutoFovSystem::new(&mut world), "auto_fov", &["prefab"])
.with(ShowFovSystem::new(&mut world), "show_fov", &["auto_fov"])
.with(AutoFovSystem::new(), "auto_fov", &["prefab"])
.with(ShowFovSystem::new(), "show_fov", &["auto_fov"])
.with_bundle(
RenderingBundle::<DefaultBackend>::new()
.with_plugin(
Expand Down Expand Up @@ -165,12 +165,11 @@ impl SimpleState for Example {
}
}

#[derive(SystemDesc)]
struct ShowFovSystem;

impl ShowFovSystem {
pub fn new(world: &mut World) -> Self {
use amethyst::ecs::prelude::SystemData;
<Self as System<'_>>::SystemData::setup(world);
pub fn new() -> Self {
Self
}
}
Expand Down
10 changes: 7 additions & 3 deletions examples/custom_game_data/example_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ use super::DemoState;
use amethyst::{
core::{
math::{UnitQuaternion, Vector3},
Time, Transform,
SystemDesc, Time, Transform,
},
derive::SystemDesc,
ecs::prelude::{
Entity, Join, Read, ReadStorage, System, SystemData, World, WriteExpect, WriteStorage,
},
ecs::prelude::{Entity, Join, Read, ReadStorage, System, WriteExpect, WriteStorage},
renderer::{camera::Camera, light::Light},
ui::{UiFinder, UiText},
utils::fps_counter::FpsCounter,
};

#[derive(Default)]
#[derive(Default, SystemDesc)]
pub struct ExampleSystem {
#[system_desc(skip)]
fps_display: Option<Entity>,
}

Expand Down
162 changes: 124 additions & 38 deletions examples/custom_game_data/game_data.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::marker::PhantomData;

use amethyst::{
core::{ArcThreadPool, SystemBundle},
core::{ArcThreadPool, SystemBundle, SystemDesc},
ecs::prelude::{Dispatcher, DispatcherBuilder, System, World, WorldExt},
error::Error,
DataDispose, DataInit,
Expand All @@ -24,12 +26,12 @@ impl<'a, 'b> CustomGameData<'a, 'b> {
}

/// Dispose game data, dropping the dispatcher
pub fn dispose(&mut self, mut world: &mut World) {
pub fn dispose(&mut self, world: &mut World) {
if let Some(base) = self.base.take() {
base.dispose(&mut world);
base.dispose(world);
}
if let Some(running) = self.running.take() {
running.dispose(&mut world);
running.dispose(world);
}
}
}
Expand All @@ -41,8 +43,8 @@ impl DataDispose for CustomGameData<'_, '_> {
}

pub struct CustomGameDataBuilder<'a, 'b> {
pub base: DispatcherBuilder<'a, 'b>,
pub running: DispatcherBuilder<'a, 'b>,
base_dispatcher_operations: Vec<Box<dyn DispatcherOperation<'a, 'b>>>,
running_dispatcher_operations: Vec<Box<dyn DispatcherOperation<'a, 'b>>>,
}

impl<'a, 'b> Default for CustomGameDataBuilder<'a, 'b> {
Expand All @@ -54,61 +56,145 @@ impl<'a, 'b> Default for CustomGameDataBuilder<'a, 'b> {
impl<'a, 'b> CustomGameDataBuilder<'a, 'b> {
pub fn new() -> Self {
CustomGameDataBuilder {
base: DispatcherBuilder::new(),
running: DispatcherBuilder::new(),
base_dispatcher_operations: vec![],
running_dispatcher_operations: vec![],
}
}

pub fn with_base<S>(mut self, system: S, name: &str, dependencies: &[&str]) -> Self
pub fn with_base<SD, S>(
mut self,
system_desc: SD,
name: &'static str,
dependencies: &'static [&'static str],
) -> Self
where
for<'c> S: System<'c> + Send + 'a,
SD: SystemDesc<'a, 'b, S> + 'static,
S: for<'c> System<'c> + 'static + Send,
{
self.base.add(system, name, dependencies);
let dispatcher_operation = Box::new(AddSystem {
system_desc,
name,
dependencies,
marker: PhantomData::<S>,
}) as Box<dyn DispatcherOperation<'a, 'b> + 'static>;
self.base_dispatcher_operations.push(dispatcher_operation);
self
}

pub fn with_base_bundle<B>(mut self, world: &mut World, bundle: B) -> Result<Self, Error>
pub fn with_base_bundle<B>(mut self, bundle: B) -> Self
where
B: SystemBundle<'a, 'b>,
B: SystemBundle<'a, 'b> + 'static,
{
bundle.build(world, &mut self.base)?;
Ok(self)
self.base_dispatcher_operations
.push(Box::new(AddBundle { bundle }));
self
}

pub fn with_running<S>(mut self, system: S, name: &str, dependencies: &[&str]) -> Self
pub fn with_running<SD, S>(
mut self,
system_desc: SD,
name: &'static str,
dependencies: &'static [&'static str],
) -> Self
where
for<'c> S: System<'c> + Send + 'a,
SD: SystemDesc<'a, 'b, S> + 'static,
S: for<'c> System<'c> + 'static + Send,
{
self.running.add(system, name, dependencies);
let dispatcher_operation = Box::new(AddSystem {
system_desc,
name,
dependencies,
marker: PhantomData::<S>,
}) as Box<dyn DispatcherOperation<'a, 'b> + 'static>;
self.running_dispatcher_operations
.push(dispatcher_operation);
self
}
}

impl<'a, 'b> DataInit<CustomGameData<'a, 'b>> for CustomGameDataBuilder<'a, 'b> {
fn build(self, mut world: &mut World) -> CustomGameData<'a, 'b> {
let (mut base, mut running) = {
#[cfg(not(no_threading))]
let pool = world.read_resource::<ArcThreadPool>().clone();

#[cfg(not(no_threading))]
let base = self.base.with_pool((*pool).clone()).build();
#[cfg(no_threading)]
let base = self.base.build();

#[cfg(not(no_threading))]
let running = self.running.with_pool((*pool).clone()).build();
#[cfg(no_threading)]
let running = self.running.build();

(base, running)
};

base.setup(&mut world);
running.setup(&mut world);
fn build(self, world: &mut World) -> CustomGameData<'a, 'b> {
let base = build_dispatcher(world, self.base_dispatcher_operations);
let running = build_dispatcher(world, self.running_dispatcher_operations);

CustomGameData {
base: Some(base),
running: Some(running),
}
}
}

fn build_dispatcher<'a, 'b>(
world: &mut World,
dispatcher_operations: Vec<Box<dyn DispatcherOperation<'a, 'b>>>,
) -> Dispatcher<'a, 'b> {
let mut dispatcher_builder = DispatcherBuilder::new();

#[cfg(not(no_threading))]
{
let pool = world.read_resource::<ArcThreadPool>().clone();
dispatcher_builder = dispatcher_builder.with_pool((*pool).clone());
}

dispatcher_operations
.into_iter()
.try_for_each(|dispatcher_operation| {
dispatcher_operation.exec(world, &mut dispatcher_builder)
})
.unwrap_or_else(|e| panic!("Failed to set up dispatcher: {}", e));

let mut dispatcher = dispatcher_builder.build();
dispatcher.setup(world);
dispatcher
}

/// Trait to capture deferred dispatcher builder operations.
trait DispatcherOperation<'a, 'b> {
/// Executes the dispatcher builder instruction.
fn exec(
self: Box<Self>,
world: &mut World,
dispatcher_builder: &mut DispatcherBuilder<'a, 'b>,
) -> Result<(), Error>;
}

struct AddSystem<SD, S> {
system_desc: SD,
name: &'static str,
dependencies: &'static [&'static str],
marker: PhantomData<S>,
}

impl<'a, 'b, SD, S> DispatcherOperation<'a, 'b> for AddSystem<SD, S>
where
SD: SystemDesc<'a, 'b, S>,
S: for<'s> System<'s> + Send + 'a,
{
fn exec(
self: Box<Self>,
world: &mut World,
dispatcher_builder: &mut DispatcherBuilder<'a, 'b>,
) -> Result<(), Error> {
let system = self.system_desc.build(world);
dispatcher_builder.add(system, self.name, self.dependencies);
Ok(())
}
}

struct AddBundle<B> {
bundle: B,
}

impl<'a, 'b, B> DispatcherOperation<'a, 'b> for AddBundle<B>
where
B: SystemBundle<'a, 'b>,
{
fn exec(
self: Box<Self>,
world: &mut World,
dispatcher_builder: &mut DispatcherBuilder<'a, 'b>,
) -> Result<(), Error> {
self.bundle.build(world, dispatcher_builder)?;
Ok(())
}
}
Loading

0 comments on commit 97d3d4f

Please sign in to comment.