diff --git a/Cargo.toml b/Cargo.toml index 4acbf24..9441027 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scion" -version = "0.1.0" +version = "0.2.0-alpha" authors = ["grzi "] edition = "2018" description = "Game making library on top of wgpu, winit, legion" diff --git a/examples/tetris/main.rs b/examples/tetris/main.rs new file mode 100644 index 0000000..b5ff325 --- /dev/null +++ b/examples/tetris/main.rs @@ -0,0 +1,13 @@ +use scion::Scion; +use scion::legion::system; + +#[system] +fn test(){ + log::info!("Hello all"); +} + +fn main() { + Scion::app() + .with_pausable_system(test_system(), |state| state.test()) + .run(); +} \ No newline at end of file diff --git a/src/application.rs b/src/application.rs index edb7de8..b2321ec 100644 --- a/src/application.rs +++ b/src/application.rs @@ -16,6 +16,9 @@ use crate::{ rendering::{renderer_state::RendererState, RendererType}, utils::{time::Time, window::WindowDimensions}, }; +use crate::state::GameState; +use crate::utils::legion_ext::PausableSystem; +use legion::systems::ResourceTypeId; /// `Scion` is the entry point of any application made with Scion's lib. pub struct Scion { @@ -62,6 +65,7 @@ impl Scion { self.resources.insert(Time::default()); self.resources.insert(Inputs::default()); + self.resources.insert(GameState::default()); self.apply_layers_action(LayerAction::Start); } @@ -243,6 +247,23 @@ impl ScionBuilder { self } + pub fn with_pausable_system(mut self, system: S, condition: fn(GameState) -> bool) -> Self { + let (resource_reads, _) = system.reads(); + let resource_reads = resource_reads + .iter() + .copied() + .chain(std::iter::once(ResourceTypeId::of::())) + .collect::>(); + let boxed_condition = Box::new(condition); + let pausable_system = PausableSystem{ + system, + decider: boxed_condition, + resource_reads + }; + self.schedule_builder.add_system(pausable_system); + self + } + /// Specify which render type you want to use. Note that by default if not set, `Scion` will use [`crate::rendering::RendererType::Scion2D`]. pub fn with_renderer(mut self, renderer_type: RendererType) -> Self { self.renderer = renderer_type; diff --git a/src/lib.rs b/src/lib.rs index a88680e..4cfb44d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ //! //! #[system] //! fn hello() { -//! println!("Heullo world from a system"); +//! println!("Hello world from a system"); //! } //! //! fn main() { @@ -35,3 +35,4 @@ pub mod game_layer; pub mod inputs; pub mod rendering; pub mod utils; +pub mod state; diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..233f7eb --- /dev/null +++ b/src/state.rs @@ -0,0 +1,11 @@ +/// `GameState` is a convenience Resource created to keep track of +/// diverse thing internally. It's also the resource used to create +/// pausable systems. +#[derive(Debug, Copy, Clone, Default)] +pub struct GameState {} + +impl GameState{ + pub fn test(&self)-> bool{ + true + } +} diff --git a/src/utils/legion_ext.rs b/src/utils/legion_ext.rs new file mode 100644 index 0000000..5646a1c --- /dev/null +++ b/src/utils/legion_ext.rs @@ -0,0 +1,52 @@ +use legion::systems::{Runnable, ResourceTypeId, SystemId, UnsafeResources, ResourceSet, CommandBuffer}; +use legion::storage::ComponentTypeId; +use legion::{World, Read}; +use legion::world::{ArchetypeAccess, WorldId}; +use crate::state::GameState; + +pub(crate) struct PausableSystem { + pub(crate) system: S, + pub(crate) decider: Box bool>, + pub(crate) resource_reads: Vec, +} + +impl Runnable for PausableSystem + where + S: Runnable +{ + fn name(&self) -> Option<&SystemId> { + self.system.name() + } + + fn reads(&self) -> (&[ResourceTypeId], &[ComponentTypeId]) { + let (_, components) = self.system.reads(); + (&self.resource_reads[..], components) + } + + fn writes(&self) -> (&[ResourceTypeId], &[ComponentTypeId]) { + self.system.writes() + } + + fn prepare(&mut self, world: &World) { + self.system.prepare(world) + } + + fn accesses_archetypes(&self) -> &ArchetypeAccess { + self.system.accesses_archetypes() + } + + unsafe fn run_unsafe(&mut self, world: &World, resources: &UnsafeResources) { + let resources_static = &*(resources as *const UnsafeResources); + let resource_to_check = Read::::fetch_unchecked(resources_static); + + if (self.decider)(*resource_to_check) { + return; + } else {} + + self.system.run_unsafe(world, resources); + } + + fn command_buffer_mut(&mut self, world: WorldId) -> Option<&mut CommandBuffer> { + self.system.command_buffer_mut(world) + } +} \ No newline at end of file diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 3e1d248..51a6006 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -3,3 +3,4 @@ pub mod file; pub mod logger; pub mod time; pub mod window; +pub(crate) mod legion_ext;