aztecs 0.5.0.1 → 0.6.0
raw patch · 53 files changed
+2933/−1642 lines, 53 filesdep +deepseqdep +lineardep +paralleldep −parallel-iodep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: deepseq, linear, parallel
Dependencies removed: parallel-io
Dependency ranges changed: base
API changes (from Hackage documentation)
- Data.Aztecs: -- | <a>Storage</a> of this component.
- Data.Aztecs: bundle :: forall a. (Component a, Typeable (StorageT a)) => a -> Bundle
- Data.Aztecs: class (Typeable a, Storage (StorageT a) a) => Component a where {
- Data.Aztecs: data Access m a
- Data.Aztecs: data Bundle
- Data.Aztecs: data EntityID
- Data.Aztecs: data Query m i o
- Data.Aztecs: data QueryFilter
- Data.Aztecs: data Schedule m i o
- Data.Aztecs: data SystemT m i o
- Data.Aztecs: data World
- Data.Aztecs: forever :: Monad m => Schedule m i () -> Schedule m i ()
- Data.Aztecs: runAccess :: Functor m => Access m a -> World -> m (a, World)
- Data.Aztecs: runSchedule :: Monad m => Schedule m i o -> World -> i -> m (o, World)
- Data.Aztecs: runSchedule_ :: Monad m => Schedule m () () -> m ()
- Data.Aztecs: schedule :: Monad m => SystemT m i o -> Schedule m i o
- Data.Aztecs: type StorageT a = IntMap;
- Data.Aztecs: type System i o = SystemT IO i o
- Data.Aztecs: with :: forall a. Component a => QueryFilter
- Data.Aztecs: without :: forall a. Component a => QueryFilter
- Data.Aztecs: }
- Data.Aztecs.Access: Access :: StateT World m a -> Access m a
- Data.Aztecs.Access: [unAccess] :: Access m a -> StateT World m a
- Data.Aztecs.Access: despawn :: Monad m => EntityID -> Access m ()
- Data.Aztecs.Access: insert :: (Monad m, Component a, Typeable (StorageT a)) => EntityID -> a -> Access m ()
- Data.Aztecs.Access: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Data.Aztecs.Access.Access m)
- Data.Aztecs.Access: instance GHC.Base.Functor m => GHC.Base.Functor (Data.Aztecs.Access.Access m)
- Data.Aztecs.Access: instance GHC.Base.Monad m => GHC.Base.Applicative (Data.Aztecs.Access.Access m)
- Data.Aztecs.Access: instance GHC.Base.Monad m => GHC.Base.Monad (Data.Aztecs.Access.Access m)
- Data.Aztecs.Access: lookup :: (Monad m, Component a) => EntityID -> Access m (Maybe a)
- Data.Aztecs.Access: newtype Access m a
- Data.Aztecs.Access: runAccess :: Functor m => Access m a -> World -> m (a, World)
- Data.Aztecs.Access: spawn :: Monad m => Bundle -> Access m EntityID
- Data.Aztecs.Access: spawn_ :: Monad m => Bundle -> Access m ()
- Data.Aztecs.Component: -- | <a>Storage</a> of this component.
- Data.Aztecs.Component: ComponentID :: Int -> ComponentID
- Data.Aztecs.Component: [unComponentId] :: ComponentID -> Int
- Data.Aztecs.Component: class (Typeable a, Storage (StorageT a) a) => Component a where {
- Data.Aztecs.Component: instance GHC.Classes.Eq Data.Aztecs.Component.ComponentID
- Data.Aztecs.Component: instance GHC.Classes.Ord Data.Aztecs.Component.ComponentID
- Data.Aztecs.Component: instance GHC.Show.Show Data.Aztecs.Component.ComponentID
- Data.Aztecs.Component: newtype ComponentID
- Data.Aztecs.Component: type StorageT a = IntMap;
- Data.Aztecs.Component: }
- Data.Aztecs.Entity: EntityID :: Int -> EntityID
- Data.Aztecs.Entity: [unEntityId] :: EntityID -> Int
- Data.Aztecs.Entity: instance GHC.Classes.Eq Data.Aztecs.Entity.EntityID
- Data.Aztecs.Entity: instance GHC.Classes.Ord Data.Aztecs.Entity.EntityID
- Data.Aztecs.Entity: instance GHC.Show.Show Data.Aztecs.Entity.EntityID
- Data.Aztecs.Entity: newtype EntityID
- Data.Aztecs.Query: DynamicQuery :: ![i] -> [EntityID] -> Archetype -> m ([o], Archetype) -> !i -> EntityID -> Archetype -> m (Maybe o, Archetype) -> DynamicQuery m i o
- Data.Aztecs.Query: DynamicQueryFilter :: !Set ComponentID -> !Set ComponentID -> DynamicQueryFilter
- Data.Aztecs.Query: Query :: (Components -> (ReadsWrites, Components, DynamicQuery m i o)) -> Query m i o
- Data.Aztecs.Query: QueryFilter :: (Components -> (DynamicQueryFilter, Components)) -> QueryFilter
- Data.Aztecs.Query: ReadsWrites :: !Set ComponentID -> !Set ComponentID -> ReadsWrites
- Data.Aztecs.Query: [dynQueryAll] :: DynamicQuery m i o -> ![i] -> [EntityID] -> Archetype -> m ([o], Archetype)
- Data.Aztecs.Query: [dynQueryLookup] :: DynamicQuery m i o -> !i -> EntityID -> Archetype -> m (Maybe o, Archetype)
- Data.Aztecs.Query: [filterWith] :: DynamicQueryFilter -> !Set ComponentID
- Data.Aztecs.Query: [filterWithout] :: DynamicQueryFilter -> !Set ComponentID
- Data.Aztecs.Query: [reads] :: ReadsWrites -> !Set ComponentID
- Data.Aztecs.Query: [runQueryFilter] :: QueryFilter -> Components -> (DynamicQueryFilter, Components)
- Data.Aztecs.Query: [runQuery] :: Query m i o -> Components -> (ReadsWrites, Components, DynamicQuery m i o)
- Data.Aztecs.Query: [writes] :: ReadsWrites -> !Set ComponentID
- Data.Aztecs.Query: all :: Monad m => Query m () a -> World -> m ([a], World)
- Data.Aztecs.Query: data DynamicQuery m i o
- Data.Aztecs.Query: data DynamicQueryFilter
- Data.Aztecs.Query: data ReadsWrites
- Data.Aztecs.Query: disjoint :: ReadsWrites -> ReadsWrites -> Bool
- Data.Aztecs.Query: entity :: Applicative m => Query m () EntityID
- Data.Aztecs.Query: entityDyn :: Applicative m => DynamicQuery m i EntityID
- Data.Aztecs.Query: fetch :: forall m a. (Applicative m, Component a) => Query m () a
- Data.Aztecs.Query: fetchDyn :: forall m a. (Applicative m, Component a) => ComponentID -> DynamicQuery m () a
- Data.Aztecs.Query: fetchMaybe :: forall m a. (Applicative m, Component a) => Query m () (Maybe a)
- Data.Aztecs.Query: fetchMaybeDyn :: forall m a. (Applicative m, Component a) => ComponentID -> DynamicQuery m () (Maybe a)
- Data.Aztecs.Query: instance GHC.Base.Functor m => GHC.Base.Functor (Data.Aztecs.Query.DynamicQuery m i)
- Data.Aztecs.Query: instance GHC.Base.Functor m => GHC.Base.Functor (Data.Aztecs.Query.Query m i)
- Data.Aztecs.Query: instance GHC.Base.Monad m => Control.Arrow.Arrow (Data.Aztecs.Query.DynamicQuery m)
- Data.Aztecs.Query: instance GHC.Base.Monad m => Control.Arrow.Arrow (Data.Aztecs.Query.Query m)
- Data.Aztecs.Query: instance GHC.Base.Monad m => Control.Category.Category (Data.Aztecs.Query.DynamicQuery m)
- Data.Aztecs.Query: instance GHC.Base.Monad m => Control.Category.Category (Data.Aztecs.Query.Query m)
- Data.Aztecs.Query: instance GHC.Base.Monad m => GHC.Base.Applicative (Data.Aztecs.Query.DynamicQuery m i)
- Data.Aztecs.Query: instance GHC.Base.Monad m => GHC.Base.Applicative (Data.Aztecs.Query.Query m i)
- Data.Aztecs.Query: instance GHC.Base.Monoid Data.Aztecs.Query.DynamicQueryFilter
- Data.Aztecs.Query: instance GHC.Base.Monoid Data.Aztecs.Query.QueryFilter
- Data.Aztecs.Query: instance GHC.Base.Monoid Data.Aztecs.Query.ReadsWrites
- Data.Aztecs.Query: instance GHC.Base.Semigroup Data.Aztecs.Query.DynamicQueryFilter
- Data.Aztecs.Query: instance GHC.Base.Semigroup Data.Aztecs.Query.QueryFilter
- Data.Aztecs.Query: instance GHC.Base.Semigroup Data.Aztecs.Query.ReadsWrites
- Data.Aztecs.Query: instance GHC.Show.Show Data.Aztecs.Query.ReadsWrites
- Data.Aztecs.Query: newtype Query m i o
- Data.Aztecs.Query: newtype QueryFilter
- Data.Aztecs.Query: set :: forall m a. (Applicative m, Component a) => Query m a a
- Data.Aztecs.Query: setDyn :: forall m a. (Applicative m, Component a) => ComponentID -> DynamicQuery m a a
- Data.Aztecs.Query: task :: Monad m => (i -> m o) -> Query m i o
- Data.Aztecs.Query: with :: forall a. Component a => QueryFilter
- Data.Aztecs.Query: without :: forall a. Component a => QueryFilter
- Data.Aztecs.Schedule: Schedule :: (Components -> (i -> Access m o, Components)) -> Schedule m i o
- Data.Aztecs.Schedule: [runSchedule'] :: Schedule m i o -> Components -> (i -> Access m o, Components)
- Data.Aztecs.Schedule: forever :: Monad m => Schedule m i () -> Schedule m i ()
- Data.Aztecs.Schedule: instance Control.Arrow.Arrow (Data.Aztecs.Schedule.Schedule GHC.Types.IO)
- Data.Aztecs.Schedule: instance GHC.Base.Monad m => Control.Category.Category (Data.Aztecs.Schedule.Schedule m)
- Data.Aztecs.Schedule: newtype Schedule m i o
- Data.Aztecs.Schedule: runSchedule :: Monad m => Schedule m i o -> World -> i -> m (o, World)
- Data.Aztecs.Schedule: runSchedule_ :: Monad m => Schedule m () () -> m ()
- Data.Aztecs.Schedule: schedule :: Monad m => SystemT m i o -> Schedule m i o
- Data.Aztecs.Storage: all :: Storage s a => s a -> [(Int, a)]
- Data.Aztecs.Storage: class (Typeable (s a), Typeable a) => Storage s a
- Data.Aztecs.Storage: fromAscList :: Storage s a => [(Int, a)] -> s a
- Data.Aztecs.Storage: insert :: Storage s a => Int -> a -> s a -> s a
- Data.Aztecs.Storage: instance Data.Typeable.Internal.Typeable a => Data.Aztecs.Storage.Storage Data.IntMap.Internal.IntMap a
- Data.Aztecs.Storage: lookup :: Storage s a => Int -> s a -> Maybe a
- Data.Aztecs.Storage: remove :: Storage s a => Int -> s a -> (Maybe a, s a)
- Data.Aztecs.Storage: singleton :: Storage s a => Int -> a -> s a
- Data.Aztecs.System: DynamicSystemT :: (World -> i -> m (o, View, Access m ())) -> DynamicSystemT m i o
- Data.Aztecs.System: SystemT :: (Components -> (DynamicSystemT m i o, ReadsWrites, Components)) -> SystemT m i o
- Data.Aztecs.System: [runSystemTDyn] :: DynamicSystemT m i o -> World -> i -> m (o, View, Access m ())
- Data.Aztecs.System: [runSystemT] :: SystemT m i o -> Components -> (DynamicSystemT m i o, ReadsWrites, Components)
- Data.Aztecs.System: all :: Monad m => Query m i a -> SystemT m i [a]
- Data.Aztecs.System: allDyn :: Monad m => Set ComponentID -> DynamicQuery m i o -> DynamicSystemT m i [o]
- Data.Aztecs.System: filter :: Monad m => Query m () a -> QueryFilter -> SystemT m () [a]
- Data.Aztecs.System: filterDyn :: Monad m => Set ComponentID -> DynamicQuery m i o -> (Node -> Bool) -> DynamicSystemT m i [o]
- Data.Aztecs.System: filterMap :: Monad m => Query m i a -> QueryFilter -> SystemT m i [a]
- Data.Aztecs.System: filterMapDyn :: Monad m => Set ComponentID -> DynamicQuery m i o -> (Node -> Bool) -> DynamicSystemT m i [o]
- Data.Aztecs.System: instance Control.Arrow.Arrow (Data.Aztecs.System.SystemT GHC.Types.IO)
- Data.Aztecs.System: instance GHC.Base.Functor m => GHC.Base.Functor (Data.Aztecs.System.DynamicSystemT m i)
- Data.Aztecs.System: instance GHC.Base.Functor m => GHC.Base.Functor (Data.Aztecs.System.SystemT m i)
- Data.Aztecs.System: instance GHC.Base.Monad m => Control.Arrow.Arrow (Data.Aztecs.System.DynamicSystemT m)
- Data.Aztecs.System: instance GHC.Base.Monad m => Control.Category.Category (Data.Aztecs.System.DynamicSystemT m)
- Data.Aztecs.System: instance GHC.Base.Monad m => Control.Category.Category (Data.Aztecs.System.SystemT m)
- Data.Aztecs.System: map :: Monad m => Query m i a -> SystemT m i [a]
- Data.Aztecs.System: mapDyn :: Monad m => Set ComponentID -> DynamicQuery m i o -> DynamicSystemT m i [o]
- Data.Aztecs.System: mapSingle :: Monad m => Query m i a -> SystemT m i a
- Data.Aztecs.System: map_ :: Monad m => Query m i o -> SystemT m i ()
- Data.Aztecs.System: newtype DynamicSystemT m i o
- Data.Aztecs.System: newtype SystemT m i o
- Data.Aztecs.System: queue :: Monad m => (i -> Access m ()) -> SystemT m i ()
- Data.Aztecs.System: queueDyn :: Monad m => (i -> Access m ()) -> DynamicSystemT m i ()
- Data.Aztecs.System: raceDyn :: DynamicSystemT IO i a -> DynamicSystemT IO i b -> DynamicSystemT IO i (a, b)
- Data.Aztecs.System: single :: Monad m => Query m () a -> SystemT m () a
- Data.Aztecs.System: singleDyn :: Monad m => Set ComponentID -> DynamicQuery m () a -> DynamicSystemT m () a
- Data.Aztecs.System: task :: Monad m => (i -> m o) -> SystemT m i o
- Data.Aztecs.System: type System i o = SystemT IO i o
- Data.Aztecs.View: View :: Map ArchetypeID Node -> View
- Data.Aztecs.View: [viewArchetypes] :: View -> Map ArchetypeID Node
- Data.Aztecs.View: allDyn :: Monad m => i -> DynamicQuery m i a -> View -> m ([a], View)
- Data.Aztecs.View: filterView :: Set ComponentID -> (Node -> Bool) -> Archetypes -> View
- Data.Aztecs.View: instance GHC.Base.Monoid Data.Aztecs.View.View
- Data.Aztecs.View: instance GHC.Base.Semigroup Data.Aztecs.View.View
- Data.Aztecs.View: instance GHC.Show.Show Data.Aztecs.View.View
- Data.Aztecs.View: newtype View
- Data.Aztecs.View: unview :: View -> World -> World
- Data.Aztecs.View: view :: Set ComponentID -> Archetypes -> View
- Data.Aztecs.World: World :: !Archetypes -> !Components -> !Map EntityID ArchetypeID -> !EntityID -> World
- Data.Aztecs.World: [archetypes] :: World -> !Archetypes
- Data.Aztecs.World: [components] :: World -> !Components
- Data.Aztecs.World: [entities] :: World -> !Map EntityID ArchetypeID
- Data.Aztecs.World: [nextEntityId] :: World -> !EntityID
- Data.Aztecs.World: data World
- Data.Aztecs.World: despawn :: EntityID -> World -> (Map ComponentID Dynamic, World)
- Data.Aztecs.World: empty :: World
- Data.Aztecs.World: insert :: forall a. (Component a, Typeable (StorageT a)) => EntityID -> a -> World -> World
- Data.Aztecs.World: insertWithId :: (Component a, Typeable (StorageT a)) => EntityID -> ComponentID -> a -> World -> World
- Data.Aztecs.World: instance GHC.Show.Show Data.Aztecs.World.World
- Data.Aztecs.World: lookup :: forall a. Component a => EntityID -> World -> Maybe a
- Data.Aztecs.World: spawn :: Bundle -> World -> (EntityID, World)
- Data.Aztecs.World: spawnComponent :: forall a. (Component a, Typeable (StorageT a)) => a -> World -> (EntityID, World)
- Data.Aztecs.World: spawnEmpty :: World -> (EntityID, World)
- Data.Aztecs.World: spawnWithArchetypeId :: forall a. (Component a, Typeable (StorageT a)) => a -> ComponentID -> ArchetypeID -> World -> (EntityID, World)
- Data.Aztecs.World: spawnWithId :: forall a. (Component a, Typeable (StorageT a)) => ComponentID -> a -> World -> (EntityID, World)
- Data.Aztecs.World.Archetype: AnyStorage :: !Dynamic -> !Int -> Dynamic -> Dynamic -> Dynamic -> !Int -> Dynamic -> (Maybe Dynamic, Dynamic) -> !Int -> Dynamic -> (Maybe AnyStorage, Dynamic) -> !Dynamic -> [Int] -> AnyStorage
- Data.Aztecs.World.Archetype: Archetype :: Map ComponentID AnyStorage -> Archetype
- Data.Aztecs.World.Archetype: Bundle :: (Components -> (Set ComponentID, Components, DynamicBundle)) -> Bundle
- Data.Aztecs.World.Archetype: DynamicBundle :: (EntityID -> Archetype -> Archetype) -> DynamicBundle
- Data.Aztecs.World.Archetype: [entitiesDyn] :: AnyStorage -> !Dynamic -> [Int]
- Data.Aztecs.World.Archetype: [insertDyn] :: AnyStorage -> !Int -> Dynamic -> Dynamic -> Dynamic
- Data.Aztecs.World.Archetype: [removeAny] :: AnyStorage -> !Int -> Dynamic -> (Maybe AnyStorage, Dynamic)
- Data.Aztecs.World.Archetype: [removeDyn] :: AnyStorage -> !Int -> Dynamic -> (Maybe Dynamic, Dynamic)
- Data.Aztecs.World.Archetype: [runDynamicBundle] :: DynamicBundle -> EntityID -> Archetype -> Archetype
- Data.Aztecs.World.Archetype: [storageDyn] :: AnyStorage -> !Dynamic
- Data.Aztecs.World.Archetype: [storages] :: Archetype -> Map ComponentID AnyStorage
- Data.Aztecs.World.Archetype: [unBundle] :: Bundle -> Components -> (Set ComponentID, Components, DynamicBundle)
- Data.Aztecs.World.Archetype: all :: Component a => ComponentID -> Archetype -> [(EntityID, a)]
- Data.Aztecs.World.Archetype: allMaybe :: Component a => ComponentID -> Archetype -> [(EntityID, Maybe a)]
- Data.Aztecs.World.Archetype: anyStorage :: forall s a. Storage s a => s a -> AnyStorage
- Data.Aztecs.World.Archetype: bundle :: forall a. (Component a, Typeable (StorageT a)) => a -> Bundle
- Data.Aztecs.World.Archetype: data AnyStorage
- Data.Aztecs.World.Archetype: dynBundle :: (Component a, Typeable (StorageT a)) => ComponentID -> a -> DynamicBundle
- Data.Aztecs.World.Archetype: empty :: Archetype
- Data.Aztecs.World.Archetype: entities :: Archetype -> [EntityID]
- Data.Aztecs.World.Archetype: insertAscList :: forall a. Component a => ComponentID -> [(EntityID, a)] -> Archetype -> Archetype
- Data.Aztecs.World.Archetype: insertComponent :: forall a. Component a => EntityID -> ComponentID -> a -> Archetype -> Archetype
- Data.Aztecs.World.Archetype: instance GHC.Base.Monoid Data.Aztecs.World.Archetype.Bundle
- Data.Aztecs.World.Archetype: instance GHC.Base.Monoid Data.Aztecs.World.Archetype.DynamicBundle
- Data.Aztecs.World.Archetype: instance GHC.Base.Semigroup Data.Aztecs.World.Archetype.Bundle
- Data.Aztecs.World.Archetype: instance GHC.Base.Semigroup Data.Aztecs.World.Archetype.DynamicBundle
- Data.Aztecs.World.Archetype: instance GHC.Show.Show Data.Aztecs.World.Archetype.AnyStorage
- Data.Aztecs.World.Archetype: instance GHC.Show.Show Data.Aztecs.World.Archetype.Archetype
- Data.Aztecs.World.Archetype: lookupComponent :: forall a. Component a => EntityID -> ComponentID -> Archetype -> Maybe a
- Data.Aztecs.World.Archetype: lookupStorage :: Component a => ComponentID -> Archetype -> Maybe (StorageT a a)
- Data.Aztecs.World.Archetype: member :: ComponentID -> Archetype -> Bool
- Data.Aztecs.World.Archetype: newtype Archetype
- Data.Aztecs.World.Archetype: newtype Bundle
- Data.Aztecs.World.Archetype: newtype DynamicBundle
- Data.Aztecs.World.Archetype: remove :: EntityID -> Archetype -> (Map ComponentID Dynamic, Archetype)
- Data.Aztecs.World.Archetype: removeStorages :: EntityID -> Archetype -> (Map ComponentID AnyStorage, Archetype)
- Data.Aztecs.World.Archetype: runBundle :: Bundle -> Components -> EntityID -> Archetype -> (Components, Archetype)
- Data.Aztecs.World.Archetype: withAscList :: forall a. Component a => ComponentID -> [a] -> Archetype -> Archetype
- Data.Aztecs.World.Archetypes: ArchetypeID :: Int -> ArchetypeID
- Data.Aztecs.World.Archetypes: Archetypes :: !Map ArchetypeID Node -> !Map (Set ComponentID) ArchetypeID -> !ArchetypeID -> !Map ComponentID (Set ArchetypeID) -> Archetypes
- Data.Aztecs.World.Archetypes: Node :: !Set ComponentID -> !Archetype -> !Map ComponentID ArchetypeID -> !Map ComponentID ArchetypeID -> Node
- Data.Aztecs.World.Archetypes: [archetypeIds] :: Archetypes -> !Map (Set ComponentID) ArchetypeID
- Data.Aztecs.World.Archetypes: [componentIds] :: Archetypes -> !Map ComponentID (Set ArchetypeID)
- Data.Aztecs.World.Archetypes: [nextArchetypeId] :: Archetypes -> !ArchetypeID
- Data.Aztecs.World.Archetypes: [nodeAdd] :: Node -> !Map ComponentID ArchetypeID
- Data.Aztecs.World.Archetypes: [nodeArchetype] :: Node -> !Archetype
- Data.Aztecs.World.Archetypes: [nodeComponentIds] :: Node -> !Set ComponentID
- Data.Aztecs.World.Archetypes: [nodeRemove] :: Node -> !Map ComponentID ArchetypeID
- Data.Aztecs.World.Archetypes: [nodes] :: Archetypes -> !Map ArchetypeID Node
- Data.Aztecs.World.Archetypes: [unArchetypeId] :: ArchetypeID -> Int
- Data.Aztecs.World.Archetypes: adjustArchetype :: ArchetypeID -> (Archetype -> Archetype) -> Archetypes -> Archetypes
- Data.Aztecs.World.Archetypes: data Archetypes
- Data.Aztecs.World.Archetypes: data Node
- Data.Aztecs.World.Archetypes: empty :: Archetypes
- Data.Aztecs.World.Archetypes: findArchetypeIds :: Set ComponentID -> Archetypes -> Set ArchetypeID
- Data.Aztecs.World.Archetypes: insertArchetype :: Set ComponentID -> Node -> Archetypes -> (ArchetypeID, Archetypes)
- Data.Aztecs.World.Archetypes: instance GHC.Classes.Eq Data.Aztecs.World.Archetypes.ArchetypeID
- Data.Aztecs.World.Archetypes: instance GHC.Classes.Ord Data.Aztecs.World.Archetypes.ArchetypeID
- Data.Aztecs.World.Archetypes: instance GHC.Show.Show Data.Aztecs.World.Archetypes.ArchetypeID
- Data.Aztecs.World.Archetypes: instance GHC.Show.Show Data.Aztecs.World.Archetypes.Archetypes
- Data.Aztecs.World.Archetypes: instance GHC.Show.Show Data.Aztecs.World.Archetypes.Node
- Data.Aztecs.World.Archetypes: lookup :: Set ComponentID -> Archetypes -> Map ArchetypeID Node
- Data.Aztecs.World.Archetypes: lookupArchetypeId :: Set ComponentID -> Archetypes -> Maybe ArchetypeID
- Data.Aztecs.World.Archetypes: lookupNode :: ArchetypeID -> Archetypes -> Maybe Node
- Data.Aztecs.World.Archetypes: map :: Set ComponentID -> (Archetype -> (a, Archetype)) -> Archetypes -> ([a], Archetypes)
- Data.Aztecs.World.Archetypes: newtype ArchetypeID
- Data.Aztecs.World.Components: ComponentID :: Int -> ComponentID
- Data.Aztecs.World.Components: Components :: !Map TypeRep ComponentID -> !ComponentID -> Components
- Data.Aztecs.World.Components: [componentIds] :: Components -> !Map TypeRep ComponentID
- Data.Aztecs.World.Components: [nextComponentId] :: Components -> !ComponentID
- Data.Aztecs.World.Components: [unComponentId] :: ComponentID -> Int
- Data.Aztecs.World.Components: data Components
- Data.Aztecs.World.Components: empty :: Components
- Data.Aztecs.World.Components: insert :: forall a. Component a => Components -> (ComponentID, Components)
- Data.Aztecs.World.Components: insert' :: forall c. Component c => Components -> (ComponentID, Components)
- Data.Aztecs.World.Components: instance GHC.Show.Show Data.Aztecs.World.Components.Components
- Data.Aztecs.World.Components: lookup :: forall a. Typeable a => Components -> Maybe ComponentID
- Data.Aztecs.World.Components: newtype ComponentID
+ Aztecs: Camera :: !V2 Int -> !V2 Float -> Camera
+ Aztecs: CameraTarget :: EntityID -> CameraTarget
+ Aztecs: Key0 :: Key
+ Aztecs: Key1 :: Key
+ Aztecs: Key2 :: Key
+ Aztecs: Key3 :: Key
+ Aztecs: Key4 :: Key
+ Aztecs: Key5 :: Key
+ Aztecs: Key6 :: Key
+ Aztecs: Key7 :: Key
+ Aztecs: Key8 :: Key
+ Aztecs: Key9 :: Key
+ Aztecs: KeyA :: Key
+ Aztecs: KeyAlt :: Key
+ Aztecs: KeyB :: Key
+ Aztecs: KeyBackslash :: Key
+ Aztecs: KeyBackspace :: Key
+ Aztecs: KeyBracketLeft :: Key
+ Aztecs: KeyBracketRight :: Key
+ Aztecs: KeyC :: Key
+ Aztecs: KeyCapsLock :: Key
+ Aztecs: KeyComma :: Key
+ Aztecs: KeyCtrl :: Key
+ Aztecs: KeyD :: Key
+ Aztecs: KeyDelete :: Key
+ Aztecs: KeyDown :: Key
+ Aztecs: KeyE :: Key
+ Aztecs: KeyEnd :: Key
+ Aztecs: KeyEnter :: Key
+ Aztecs: KeyEquals :: Key
+ Aztecs: KeyEscape :: Key
+ Aztecs: KeyF :: Key
+ Aztecs: KeyF1 :: Key
+ Aztecs: KeyF10 :: Key
+ Aztecs: KeyF11 :: Key
+ Aztecs: KeyF12 :: Key
+ Aztecs: KeyF2 :: Key
+ Aztecs: KeyF3 :: Key
+ Aztecs: KeyF4 :: Key
+ Aztecs: KeyF5 :: Key
+ Aztecs: KeyF6 :: Key
+ Aztecs: KeyF7 :: Key
+ Aztecs: KeyF8 :: Key
+ Aztecs: KeyF9 :: Key
+ Aztecs: KeyG :: Key
+ Aztecs: KeyH :: Key
+ Aztecs: KeyHome :: Key
+ Aztecs: KeyI :: Key
+ Aztecs: KeyInsert :: Key
+ Aztecs: KeyJ :: Key
+ Aztecs: KeyK :: Key
+ Aztecs: KeyL :: Key
+ Aztecs: KeyLeft :: Key
+ Aztecs: KeyM :: Key
+ Aztecs: KeyMenu :: Key
+ Aztecs: KeyMinus :: Key
+ Aztecs: KeyN :: Key
+ Aztecs: KeyNumLock :: Key
+ Aztecs: KeyNumpad0 :: Key
+ Aztecs: KeyNumpad1 :: Key
+ Aztecs: KeyNumpad2 :: Key
+ Aztecs: KeyNumpad3 :: Key
+ Aztecs: KeyNumpad4 :: Key
+ Aztecs: KeyNumpad5 :: Key
+ Aztecs: KeyNumpad6 :: Key
+ Aztecs: KeyNumpad7 :: Key
+ Aztecs: KeyNumpad8 :: Key
+ Aztecs: KeyNumpad9 :: Key
+ Aztecs: KeyNumpadDivide :: Key
+ Aztecs: KeyNumpadEnter :: Key
+ Aztecs: KeyNumpadMinus :: Key
+ Aztecs: KeyNumpadMultiply :: Key
+ Aztecs: KeyNumpadPeriod :: Key
+ Aztecs: KeyNumpadPlus :: Key
+ Aztecs: KeyO :: Key
+ Aztecs: KeyP :: Key
+ Aztecs: KeyPageDown :: Key
+ Aztecs: KeyPageUp :: Key
+ Aztecs: KeyPeriod :: Key
+ Aztecs: KeyQ :: Key
+ Aztecs: KeyR :: Key
+ Aztecs: KeyRight :: Key
+ Aztecs: KeyS :: Key
+ Aztecs: KeySemicolon :: Key
+ Aztecs: KeyShift :: Key
+ Aztecs: KeySlash :: Key
+ Aztecs: KeySpace :: Key
+ Aztecs: KeySuper :: Key
+ Aztecs: KeyT :: Key
+ Aztecs: KeyTab :: Key
+ Aztecs: KeyU :: Key
+ Aztecs: KeyUp :: Key
+ Aztecs: KeyV :: Key
+ Aztecs: KeyW :: Key
+ Aztecs: KeyX :: Key
+ Aztecs: KeyY :: Key
+ Aztecs: KeyZ :: Key
+ Aztecs: KeyboardInput :: !Map Key InputMotion -> !Set Key -> KeyboardInput
+ Aztecs: MouseInput :: !Point V2 Int -> !V2 Int -> !Map MouseButton InputMotion -> MouseInput
+ Aztecs: Time :: Word32 -> Time
+ Aztecs: Transform :: !V2 Int -> !Float -> !V2 Int -> Transform
+ Aztecs: Window :: !String -> Window
+ Aztecs: [cameraScale] :: Camera -> !V2 Float
+ Aztecs: [cameraTargetWindow] :: CameraTarget -> EntityID
+ Aztecs: [cameraViewport] :: Camera -> !V2 Int
+ Aztecs: [elapsedMS] :: Time -> Word32
+ Aztecs: [keyboardEvents] :: KeyboardInput -> !Map Key InputMotion
+ Aztecs: [keyboardPressed] :: KeyboardInput -> !Set Key
+ Aztecs: [mouseButtons] :: MouseInput -> !Map MouseButton InputMotion
+ Aztecs: [mouseOffset] :: MouseInput -> !V2 Int
+ Aztecs: [mousePosition] :: MouseInput -> !Point V2 Int
+ Aztecs: [transformPosition] :: Transform -> !V2 Int
+ Aztecs: [transformRotation] :: Transform -> !Float
+ Aztecs: [transformScale] :: Transform -> !V2 Int
+ Aztecs: [windowTitle] :: Window -> !String
+ Aztecs: asset :: MonadAssetLoader a m => FilePath -> AssetConfig a -> m (Handle a)
+ Aztecs: data Camera
+ Aztecs: data Key
+ Aztecs: data KeyboardInput
+ Aztecs: data MouseInput
+ Aztecs: data Transform
+ Aztecs: data Window
+ Aztecs: isKeyPressed :: Key -> KeyboardInput -> Bool
+ Aztecs: load :: (ArrowSystem Query arr, Asset a) => AssetLoader a o -> arr () o
+ Aztecs: newtype CameraTarget
+ Aztecs: newtype Time
+ Aztecs: transform :: Transform
+ Aztecs: wasKeyPressed :: Key -> KeyboardInput -> Bool
+ Aztecs: wasKeyReleased :: Key -> KeyboardInput -> Bool
+ Aztecs.Asset: AssetId :: Int -> AssetId
+ Aztecs.Asset: AssetLoaderT :: StateT (AssetServer a) m o -> AssetLoaderT a m o
+ Aztecs.Asset: AssetServer :: !Map AssetId a -> !Map AssetId (Either (IO (IORef (Maybe a))) (IORef (Maybe a))) -> !AssetId -> AssetServer a
+ Aztecs.Asset: Handle :: AssetId -> Handle a
+ Aztecs.Asset: [assetServerAssets] :: AssetServer a -> !Map AssetId a
+ Aztecs.Asset: [handleId] :: Handle a -> AssetId
+ Aztecs.Asset: [loadingAssets] :: AssetServer a -> !Map AssetId (Either (IO (IORef (Maybe a))) (IORef (Maybe a)))
+ Aztecs.Asset: [nextAssetId] :: AssetServer a -> !AssetId
+ Aztecs.Asset: [unAssetId] :: AssetId -> Int
+ Aztecs.Asset: [unAssetLoader] :: AssetLoaderT a m o -> StateT (AssetServer a) m o
+ Aztecs.Asset: asset :: MonadAssetLoader a m => FilePath -> AssetConfig a -> m (Handle a)
+ Aztecs.Asset: class (Typeable a) => Asset a where {
+ Aztecs.Asset: class MonadAssetLoader a m | m -> a
+ Aztecs.Asset: data AssetServer a
+ Aztecs.Asset: empty :: AssetServer a
+ Aztecs.Asset: instance (GHC.Base.Monad m, Aztecs.Asset.Asset a) => Aztecs.Asset.MonadAssetLoader a (Aztecs.Asset.AssetLoaderT a m)
+ Aztecs.Asset: instance Control.DeepSeq.NFData (Aztecs.Asset.AssetServer a)
+ Aztecs.Asset: instance Control.DeepSeq.NFData (Aztecs.Asset.Handle a)
+ Aztecs.Asset: instance Data.Typeable.Internal.Typeable a => Aztecs.ECS.Component.Component (Aztecs.Asset.AssetServer a)
+ Aztecs.Asset: instance GHC.Base.Functor m => GHC.Base.Functor (Aztecs.Asset.AssetLoaderT a m)
+ Aztecs.Asset: instance GHC.Base.Monad m => GHC.Base.Applicative (Aztecs.Asset.AssetLoaderT a m)
+ Aztecs.Asset: instance GHC.Base.Monad m => GHC.Base.Monad (Aztecs.Asset.AssetLoaderT a m)
+ Aztecs.Asset: instance GHC.Classes.Eq (Aztecs.Asset.Handle a)
+ Aztecs.Asset: instance GHC.Classes.Eq Aztecs.Asset.AssetId
+ Aztecs.Asset: instance GHC.Classes.Ord (Aztecs.Asset.Handle a)
+ Aztecs.Asset: instance GHC.Classes.Ord Aztecs.Asset.AssetId
+ Aztecs.Asset: instance GHC.Generics.Generic (Aztecs.Asset.AssetServer a)
+ Aztecs.Asset: instance GHC.Show.Show (Aztecs.Asset.Handle a)
+ Aztecs.Asset: instance GHC.Show.Show Aztecs.Asset.AssetId
+ Aztecs.Asset: load :: (ArrowSystem Query arr, Asset a) => AssetLoader a o -> arr () o
+ Aztecs.Asset: loadAsset :: Asset a => FilePath -> AssetConfig a -> IO a
+ Aztecs.Asset: loadAssets :: forall a. Typeable a => Schedule IO () ()
+ Aztecs.Asset: loadQuery :: (Asset a, ArrowQuery arr) => AssetLoader a o -> arr () o
+ Aztecs.Asset: lookupAsset :: Handle a -> AssetServer a -> Maybe a
+ Aztecs.Asset: newtype AssetId
+ Aztecs.Asset: newtype AssetLoaderT a m o
+ Aztecs.Asset: newtype Handle a
+ Aztecs.Asset: setup :: forall a. Typeable a => System () ()
+ Aztecs.Asset: type AssetConfig a;
+ Aztecs.Asset: type AssetLoader a o = AssetLoaderT a Identity o
+ Aztecs.Asset: }
+ Aztecs.Camera: Camera :: !V2 Int -> !V2 Float -> Camera
+ Aztecs.Camera: CameraTarget :: EntityID -> CameraTarget
+ Aztecs.Camera: [cameraScale] :: Camera -> !V2 Float
+ Aztecs.Camera: [cameraTargetWindow] :: CameraTarget -> EntityID
+ Aztecs.Camera: [cameraViewport] :: Camera -> !V2 Int
+ Aztecs.Camera: addCameraTargets :: (ArrowQueryReader qr, ArrowReaderSystem qr arr, ArrowSystem q arr) => arr () ()
+ Aztecs.Camera: data Camera
+ Aztecs.Camera: instance Aztecs.ECS.Component.Component Aztecs.Camera.Camera
+ Aztecs.Camera: instance Aztecs.ECS.Component.Component Aztecs.Camera.CameraTarget
+ Aztecs.Camera: instance Control.DeepSeq.NFData Aztecs.Camera.Camera
+ Aztecs.Camera: instance Control.DeepSeq.NFData Aztecs.Camera.CameraTarget
+ Aztecs.Camera: instance GHC.Classes.Eq Aztecs.Camera.CameraTarget
+ Aztecs.Camera: instance GHC.Generics.Generic Aztecs.Camera.Camera
+ Aztecs.Camera: instance GHC.Generics.Generic Aztecs.Camera.CameraTarget
+ Aztecs.Camera: instance GHC.Show.Show Aztecs.Camera.Camera
+ Aztecs.Camera: instance GHC.Show.Show Aztecs.Camera.CameraTarget
+ Aztecs.Camera: newtype CameraTarget
+ Aztecs.ECS: -- | <a>Storage</a> of this component.
+ Aztecs.ECS: access :: Monad m => (i -> AccessT m o) -> Schedule m i o
+ Aztecs.ECS: bundle :: forall a. (Component a, Typeable (StorageT a)) => a -> Bundle
+ Aztecs.ECS: class (Typeable a, Storage (StorageT a) a) => Component a where {
+ Aztecs.ECS: data Bundle
+ Aztecs.ECS: data EntityID
+ Aztecs.ECS: data Query i o
+ Aztecs.ECS: data QueryFilter
+ Aztecs.ECS: data Schedule m i o
+ Aztecs.ECS: data System i o
+ Aztecs.ECS: data World
+ Aztecs.ECS: forever :: Schedule IO i o -> (o -> IO ()) -> Schedule IO i ()
+ Aztecs.ECS: forever_ :: Schedule IO i o -> Schedule IO i ()
+ Aztecs.ECS: reader :: Monad m => ReaderSystem i o -> Schedule m i o
+ Aztecs.ECS: runAccessT :: Functor m => AccessT m a -> World -> m (a, World)
+ Aztecs.ECS: runSchedule :: Monad m => Schedule m i o -> World -> i -> m (o, World)
+ Aztecs.ECS: runSchedule_ :: Monad m => Schedule m () () -> m ()
+ Aztecs.ECS: system :: Monad m => System i o -> Schedule m i o
+ Aztecs.ECS: task :: Monad m => (i -> m o) -> Schedule m i o
+ Aztecs.ECS: type Access = AccessT Identity
+ Aztecs.ECS: type StorageT a = IntMap;
+ Aztecs.ECS: with :: forall a. Component a => QueryFilter
+ Aztecs.ECS: without :: forall a. Component a => QueryFilter
+ Aztecs.ECS: }
+ Aztecs.ECS.Access: AccessT :: StateT World m a -> AccessT m a
+ Aztecs.ECS.Access: [unAccessT] :: AccessT m a -> StateT World m a
+ Aztecs.ECS.Access: class (Monad m) => MonadAccess m
+ Aztecs.ECS.Access: despawn :: MonadAccess m => EntityID -> m ()
+ Aztecs.ECS.Access: insert :: (MonadAccess m, Component a, Typeable (StorageT a)) => EntityID -> a -> m ()
+ Aztecs.ECS.Access: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Aztecs.ECS.Access.AccessT m)
+ Aztecs.ECS.Access: instance GHC.Base.Functor m => GHC.Base.Functor (Aztecs.ECS.Access.AccessT m)
+ Aztecs.ECS.Access: instance GHC.Base.Monad m => Aztecs.ECS.Access.Class.MonadAccess (Aztecs.ECS.Access.AccessT m)
+ Aztecs.ECS.Access: instance GHC.Base.Monad m => GHC.Base.Applicative (Aztecs.ECS.Access.AccessT m)
+ Aztecs.ECS.Access: instance GHC.Base.Monad m => GHC.Base.Monad (Aztecs.ECS.Access.AccessT m)
+ Aztecs.ECS.Access: lookup :: (MonadAccess m, Component a) => EntityID -> m (Maybe a)
+ Aztecs.ECS.Access: newtype AccessT m a
+ Aztecs.ECS.Access: remove :: (MonadAccess m, Component a, Typeable (StorageT a)) => EntityID -> m (Maybe a)
+ Aztecs.ECS.Access: runAccessT :: Functor m => AccessT m a -> World -> m (a, World)
+ Aztecs.ECS.Access: spawn :: MonadAccess m => Bundle -> m EntityID
+ Aztecs.ECS.Access: spawn_ :: MonadAccess m => Bundle -> m ()
+ Aztecs.ECS.Access: type Access = AccessT Identity
+ Aztecs.ECS.Access.Class: class (Monad m) => MonadAccess m
+ Aztecs.ECS.Access.Class: despawn :: MonadAccess m => EntityID -> m ()
+ Aztecs.ECS.Access.Class: insert :: (MonadAccess m, Component a, Typeable (StorageT a)) => EntityID -> a -> m ()
+ Aztecs.ECS.Access.Class: lookup :: (MonadAccess m, Component a) => EntityID -> m (Maybe a)
+ Aztecs.ECS.Access.Class: remove :: (MonadAccess m, Component a, Typeable (StorageT a)) => EntityID -> m (Maybe a)
+ Aztecs.ECS.Access.Class: spawn :: MonadAccess m => Bundle -> m EntityID
+ Aztecs.ECS.Access.Class: spawn_ :: MonadAccess m => Bundle -> m ()
+ Aztecs.ECS.Component: -- | <a>Storage</a> of this component.
+ Aztecs.ECS.Component: ComponentID :: Int -> ComponentID
+ Aztecs.ECS.Component: [unComponentId] :: ComponentID -> Int
+ Aztecs.ECS.Component: class (Typeable a, Storage (StorageT a) a) => Component a where {
+ Aztecs.ECS.Component: instance Control.DeepSeq.NFData Aztecs.ECS.Component.ComponentID
+ Aztecs.ECS.Component: instance GHC.Classes.Eq Aztecs.ECS.Component.ComponentID
+ Aztecs.ECS.Component: instance GHC.Classes.Ord Aztecs.ECS.Component.ComponentID
+ Aztecs.ECS.Component: instance GHC.Generics.Generic Aztecs.ECS.Component.ComponentID
+ Aztecs.ECS.Component: instance GHC.Show.Show Aztecs.ECS.Component.ComponentID
+ Aztecs.ECS.Component: newtype ComponentID
+ Aztecs.ECS.Component: type StorageT a = IntMap;
+ Aztecs.ECS.Component: }
+ Aztecs.ECS.Entity: EntityID :: Int -> EntityID
+ Aztecs.ECS.Entity: [unEntityId] :: EntityID -> Int
+ Aztecs.ECS.Entity: instance Control.DeepSeq.NFData Aztecs.ECS.Entity.EntityID
+ Aztecs.ECS.Entity: instance GHC.Classes.Eq Aztecs.ECS.Entity.EntityID
+ Aztecs.ECS.Entity: instance GHC.Classes.Ord Aztecs.ECS.Entity.EntityID
+ Aztecs.ECS.Entity: instance GHC.Generics.Generic Aztecs.ECS.Entity.EntityID
+ Aztecs.ECS.Entity: instance GHC.Show.Show Aztecs.ECS.Entity.EntityID
+ Aztecs.ECS.Entity: newtype EntityID
+ Aztecs.ECS.Query: Query :: (Components -> (ReadsWrites, Components, DynamicQuery i o)) -> Query i o
+ Aztecs.ECS.Query: QueryFilter :: (Components -> (DynamicQueryFilter, Components)) -> QueryFilter
+ Aztecs.ECS.Query: ReadsWrites :: !Set ComponentID -> !Set ComponentID -> ReadsWrites
+ Aztecs.ECS.Query: [reads] :: ReadsWrites -> !Set ComponentID
+ Aztecs.ECS.Query: [runQueryFilter] :: QueryFilter -> Components -> (DynamicQueryFilter, Components)
+ Aztecs.ECS.Query: [runQuery] :: Query i o -> Components -> (ReadsWrites, Components, DynamicQuery i o)
+ Aztecs.ECS.Query: [writes] :: ReadsWrites -> !Set ComponentID
+ Aztecs.ECS.Query: all :: Query () a -> World -> ([a], World)
+ Aztecs.ECS.Query: class (ArrowDynamicQueryReader arr) => ArrowDynamicQuery arr
+ Aztecs.ECS.Query: class (Arrow arr) => ArrowDynamicQueryReader arr
+ Aztecs.ECS.Query: class (ArrowQueryReader arr) => ArrowQuery arr
+ Aztecs.ECS.Query: class (Arrow arr) => ArrowQueryReader arr
+ Aztecs.ECS.Query: data ReadsWrites
+ Aztecs.ECS.Query: disjoint :: ReadsWrites -> ReadsWrites -> Bool
+ Aztecs.ECS.Query: entity :: ArrowQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query: entityDyn :: ArrowDynamicQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query: fetch :: (ArrowQueryReader arr, Component a) => arr () a
+ Aztecs.ECS.Query: fetchDyn :: (ArrowDynamicQueryReader arr, Component a) => ComponentID -> arr () a
+ Aztecs.ECS.Query: fetchMaybe :: (ArrowQueryReader arr, Component a) => arr () (Maybe a)
+ Aztecs.ECS.Query: fetchMaybeDyn :: (ArrowDynamicQueryReader arr, Component a) => ComponentID -> arr () (Maybe a)
+ Aztecs.ECS.Query: instance Aztecs.ECS.Query.Class.ArrowQuery Aztecs.ECS.Query.Query
+ Aztecs.ECS.Query: instance Aztecs.ECS.Query.Dynamic.Class.ArrowDynamicQuery Aztecs.ECS.Query.Query
+ Aztecs.ECS.Query: instance Aztecs.ECS.Query.Dynamic.Reader.Class.ArrowDynamicQueryReader Aztecs.ECS.Query.Query
+ Aztecs.ECS.Query: instance Aztecs.ECS.Query.Reader.Class.ArrowQueryReader Aztecs.ECS.Query.Query
+ Aztecs.ECS.Query: instance Control.Arrow.Arrow Aztecs.ECS.Query.Query
+ Aztecs.ECS.Query: instance Control.Category.Category Aztecs.ECS.Query.Query
+ Aztecs.ECS.Query: instance GHC.Base.Applicative (Aztecs.ECS.Query.Query i)
+ Aztecs.ECS.Query: instance GHC.Base.Functor (Aztecs.ECS.Query.Query i)
+ Aztecs.ECS.Query: instance GHC.Base.Monoid Aztecs.ECS.Query.ReadsWrites
+ Aztecs.ECS.Query: instance GHC.Base.Semigroup Aztecs.ECS.Query.ReadsWrites
+ Aztecs.ECS.Query: instance GHC.Show.Show Aztecs.ECS.Query.ReadsWrites
+ Aztecs.ECS.Query: newtype Query i o
+ Aztecs.ECS.Query: newtype QueryFilter
+ Aztecs.ECS.Query: set :: (ArrowQuery arr, Component a) => arr a a
+ Aztecs.ECS.Query: setDyn :: (ArrowDynamicQuery arr, Component a) => ComponentID -> arr a a
+ Aztecs.ECS.Query: with :: forall a. Component a => QueryFilter
+ Aztecs.ECS.Query: without :: forall a. Component a => QueryFilter
+ Aztecs.ECS.Query.Class: class (ArrowQueryReader arr) => ArrowQuery arr
+ Aztecs.ECS.Query.Class: set :: (ArrowQuery arr, Component a) => arr a a
+ Aztecs.ECS.Query.Dynamic: DynamicQuery :: ([i] -> [EntityID] -> Archetype -> ([o], Archetype)) -> DynamicQuery i o
+ Aztecs.ECS.Query.Dynamic: DynamicQueryFilter :: !Set ComponentID -> !Set ComponentID -> DynamicQueryFilter
+ Aztecs.ECS.Query.Dynamic: [dynQueryAll] :: DynamicQuery i o -> [i] -> [EntityID] -> Archetype -> ([o], Archetype)
+ Aztecs.ECS.Query.Dynamic: [filterWith] :: DynamicQueryFilter -> !Set ComponentID
+ Aztecs.ECS.Query.Dynamic: [filterWithout] :: DynamicQueryFilter -> !Set ComponentID
+ Aztecs.ECS.Query.Dynamic: class (ArrowDynamicQueryReader arr) => ArrowDynamicQuery arr
+ Aztecs.ECS.Query.Dynamic: class (Arrow arr) => ArrowDynamicQueryReader arr
+ Aztecs.ECS.Query.Dynamic: data DynamicQueryFilter
+ Aztecs.ECS.Query.Dynamic: entityDyn :: ArrowDynamicQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query.Dynamic: fetchDyn :: (ArrowDynamicQueryReader arr, Component a) => ComponentID -> arr () a
+ Aztecs.ECS.Query.Dynamic: fetchMaybeDyn :: (ArrowDynamicQueryReader arr, Component a) => ComponentID -> arr () (Maybe a)
+ Aztecs.ECS.Query.Dynamic: instance Aztecs.ECS.Query.Dynamic.Class.ArrowDynamicQuery Aztecs.ECS.Query.Dynamic.DynamicQuery
+ Aztecs.ECS.Query.Dynamic: instance Aztecs.ECS.Query.Dynamic.Reader.Class.ArrowDynamicQueryReader Aztecs.ECS.Query.Dynamic.DynamicQuery
+ Aztecs.ECS.Query.Dynamic: instance Control.Arrow.Arrow Aztecs.ECS.Query.Dynamic.DynamicQuery
+ Aztecs.ECS.Query.Dynamic: instance Control.Category.Category Aztecs.ECS.Query.Dynamic.DynamicQuery
+ Aztecs.ECS.Query.Dynamic: instance GHC.Base.Applicative (Aztecs.ECS.Query.Dynamic.DynamicQuery i)
+ Aztecs.ECS.Query.Dynamic: instance GHC.Base.Functor (Aztecs.ECS.Query.Dynamic.DynamicQuery i)
+ Aztecs.ECS.Query.Dynamic: newtype DynamicQuery i o
+ Aztecs.ECS.Query.Dynamic: setDyn :: (ArrowDynamicQuery arr, Component a) => ComponentID -> arr a a
+ Aztecs.ECS.Query.Dynamic.Class: class (ArrowDynamicQueryReader arr) => ArrowDynamicQuery arr
+ Aztecs.ECS.Query.Dynamic.Class: setDyn :: (ArrowDynamicQuery arr, Component a) => ComponentID -> arr a a
+ Aztecs.ECS.Query.Dynamic.Reader: DynamicQueryFilter :: !Set ComponentID -> !Set ComponentID -> DynamicQueryFilter
+ Aztecs.ECS.Query.Dynamic.Reader: DynamicQueryReader :: ([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
+ Aztecs.ECS.Query.Dynamic.Reader: [dynQueryReaderAll] :: DynamicQueryReader i o -> [i] -> [EntityID] -> Archetype -> [o]
+ Aztecs.ECS.Query.Dynamic.Reader: [filterWith] :: DynamicQueryFilter -> !Set ComponentID
+ Aztecs.ECS.Query.Dynamic.Reader: [filterWithout] :: DynamicQueryFilter -> !Set ComponentID
+ Aztecs.ECS.Query.Dynamic.Reader: class (Arrow arr) => ArrowDynamicQueryReader arr
+ Aztecs.ECS.Query.Dynamic.Reader: data DynamicQueryFilter
+ Aztecs.ECS.Query.Dynamic.Reader: entityDyn :: ArrowDynamicQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query.Dynamic.Reader: fetchDyn :: (ArrowDynamicQueryReader arr, Component a) => ComponentID -> arr () a
+ Aztecs.ECS.Query.Dynamic.Reader: fetchMaybeDyn :: (ArrowDynamicQueryReader arr, Component a) => ComponentID -> arr () (Maybe a)
+ Aztecs.ECS.Query.Dynamic.Reader: instance Aztecs.ECS.Query.Dynamic.Reader.Class.ArrowDynamicQueryReader Aztecs.ECS.Query.Dynamic.Reader.DynamicQueryReader
+ Aztecs.ECS.Query.Dynamic.Reader: instance Control.Arrow.Arrow Aztecs.ECS.Query.Dynamic.Reader.DynamicQueryReader
+ Aztecs.ECS.Query.Dynamic.Reader: instance Control.Category.Category Aztecs.ECS.Query.Dynamic.Reader.DynamicQueryReader
+ Aztecs.ECS.Query.Dynamic.Reader: instance GHC.Base.Applicative (Aztecs.ECS.Query.Dynamic.Reader.DynamicQueryReader i)
+ Aztecs.ECS.Query.Dynamic.Reader: instance GHC.Base.Functor (Aztecs.ECS.Query.Dynamic.Reader.DynamicQueryReader i)
+ Aztecs.ECS.Query.Dynamic.Reader: instance GHC.Base.Monoid Aztecs.ECS.Query.Dynamic.Reader.DynamicQueryFilter
+ Aztecs.ECS.Query.Dynamic.Reader: instance GHC.Base.Semigroup Aztecs.ECS.Query.Dynamic.Reader.DynamicQueryFilter
+ Aztecs.ECS.Query.Dynamic.Reader: newtype DynamicQueryReader i o
+ Aztecs.ECS.Query.Dynamic.Reader.Class: class (Arrow arr) => ArrowDynamicQueryReader arr
+ Aztecs.ECS.Query.Dynamic.Reader.Class: entityDyn :: ArrowDynamicQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query.Dynamic.Reader.Class: fetchDyn :: (ArrowDynamicQueryReader arr, Component a) => ComponentID -> arr () a
+ Aztecs.ECS.Query.Dynamic.Reader.Class: fetchMaybeDyn :: (ArrowDynamicQueryReader arr, Component a) => ComponentID -> arr () (Maybe a)
+ Aztecs.ECS.Query.Reader: DynamicQueryFilter :: !Set ComponentID -> !Set ComponentID -> DynamicQueryFilter
+ Aztecs.ECS.Query.Reader: Query :: (Components -> (Set ComponentID, Components, DynamicQueryReader i o)) -> QueryReader i o
+ Aztecs.ECS.Query.Reader: QueryFilter :: (Components -> (DynamicQueryFilter, Components)) -> QueryFilter
+ Aztecs.ECS.Query.Reader: [filterWith] :: DynamicQueryFilter -> !Set ComponentID
+ Aztecs.ECS.Query.Reader: [filterWithout] :: DynamicQueryFilter -> !Set ComponentID
+ Aztecs.ECS.Query.Reader: [runQueryFilter] :: QueryFilter -> Components -> (DynamicQueryFilter, Components)
+ Aztecs.ECS.Query.Reader: [runQueryReader] :: QueryReader i o -> Components -> (Set ComponentID, Components, DynamicQueryReader i o)
+ Aztecs.ECS.Query.Reader: class (Arrow arr) => ArrowDynamicQueryReader arr
+ Aztecs.ECS.Query.Reader: class (Arrow arr) => ArrowQueryReader arr
+ Aztecs.ECS.Query.Reader: data DynamicQueryFilter
+ Aztecs.ECS.Query.Reader: entity :: ArrowQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query.Reader: entityDyn :: ArrowDynamicQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query.Reader: fetch :: (ArrowQueryReader arr, Component a) => arr () a
+ Aztecs.ECS.Query.Reader: fetchDyn :: (ArrowDynamicQueryReader arr, Component a) => ComponentID -> arr () a
+ Aztecs.ECS.Query.Reader: fetchMaybe :: (ArrowQueryReader arr, Component a) => arr () (Maybe a)
+ Aztecs.ECS.Query.Reader: fetchMaybeDyn :: (ArrowDynamicQueryReader arr, Component a) => ComponentID -> arr () (Maybe a)
+ Aztecs.ECS.Query.Reader: instance Aztecs.ECS.Query.Dynamic.Reader.Class.ArrowDynamicQueryReader Aztecs.ECS.Query.Reader.QueryReader
+ Aztecs.ECS.Query.Reader: instance Aztecs.ECS.Query.Reader.Class.ArrowQueryReader Aztecs.ECS.Query.Reader.QueryReader
+ Aztecs.ECS.Query.Reader: instance Control.Arrow.Arrow Aztecs.ECS.Query.Reader.QueryReader
+ Aztecs.ECS.Query.Reader: instance Control.Category.Category Aztecs.ECS.Query.Reader.QueryReader
+ Aztecs.ECS.Query.Reader: instance GHC.Base.Applicative (Aztecs.ECS.Query.Reader.QueryReader i)
+ Aztecs.ECS.Query.Reader: instance GHC.Base.Functor (Aztecs.ECS.Query.Reader.QueryReader i)
+ Aztecs.ECS.Query.Reader: instance GHC.Base.Monoid Aztecs.ECS.Query.Reader.QueryFilter
+ Aztecs.ECS.Query.Reader: instance GHC.Base.Semigroup Aztecs.ECS.Query.Reader.QueryFilter
+ Aztecs.ECS.Query.Reader: newtype QueryFilter
+ Aztecs.ECS.Query.Reader: newtype QueryReader i o
+ Aztecs.ECS.Query.Reader: with :: forall a. Component a => QueryFilter
+ Aztecs.ECS.Query.Reader: without :: forall a. Component a => QueryFilter
+ Aztecs.ECS.Query.Reader.Class: class (Arrow arr) => ArrowQueryReader arr
+ Aztecs.ECS.Query.Reader.Class: entity :: ArrowQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query.Reader.Class: fetch :: (ArrowQueryReader arr, Component a) => arr () a
+ Aztecs.ECS.Query.Reader.Class: fetchMaybe :: (ArrowQueryReader arr, Component a) => arr () (Maybe a)
+ Aztecs.ECS.Schedule: Schedule :: (Components -> (i -> AccessT m o, Components)) -> Schedule m i o
+ Aztecs.ECS.Schedule: [runSchedule'] :: Schedule m i o -> Components -> (i -> AccessT m o, Components)
+ Aztecs.ECS.Schedule: access :: Monad m => (i -> AccessT m o) -> Schedule m i o
+ Aztecs.ECS.Schedule: forever :: Schedule IO i o -> (o -> IO ()) -> Schedule IO i ()
+ Aztecs.ECS.Schedule: forever_ :: Schedule IO i o -> Schedule IO i ()
+ Aztecs.ECS.Schedule: instance Control.Arrow.Arrow (Aztecs.ECS.Schedule.Schedule GHC.Types.IO)
+ Aztecs.ECS.Schedule: instance GHC.Base.Functor m => GHC.Base.Functor (Aztecs.ECS.Schedule.Schedule m i)
+ Aztecs.ECS.Schedule: instance GHC.Base.Monad m => Control.Category.Category (Aztecs.ECS.Schedule.Schedule m)
+ Aztecs.ECS.Schedule: newtype Schedule m i o
+ Aztecs.ECS.Schedule: reader :: Monad m => ReaderSystem i o -> Schedule m i o
+ Aztecs.ECS.Schedule: runSchedule :: Monad m => Schedule m i o -> World -> i -> m (o, World)
+ Aztecs.ECS.Schedule: runSchedule_ :: Monad m => Schedule m () () -> m ()
+ Aztecs.ECS.Schedule: system :: Monad m => System i o -> Schedule m i o
+ Aztecs.ECS.Schedule: task :: Monad m => (i -> m o) -> Schedule m i o
+ Aztecs.ECS.System: System :: (Components -> (DynamicSystem i o, ReadsWrites, Components)) -> System i o
+ Aztecs.ECS.System: [runSystem] :: System i o -> Components -> (DynamicSystem i o, ReadsWrites, Components)
+ Aztecs.ECS.System: all :: ArrowReaderSystem q arr => q i a -> arr i [a]
+ Aztecs.ECS.System: class (Arrow arr) => ArrowReaderSystem q arr | arr -> q
+ Aztecs.ECS.System: class (Arrow arr) => ArrowSystem q arr | arr -> q
+ Aztecs.ECS.System: filter :: ArrowReaderSystem q arr => q () a -> QueryFilter -> arr () [a]
+ Aztecs.ECS.System: filterMap :: ArrowSystem q arr => q i a -> QueryFilter -> arr i [a]
+ Aztecs.ECS.System: instance Aztecs.ECS.System.Class.ArrowSystem Aztecs.ECS.Query.Query Aztecs.ECS.System.System
+ Aztecs.ECS.System: instance Aztecs.ECS.System.Reader.Class.ArrowReaderSystem Aztecs.ECS.Query.Reader.QueryReader Aztecs.ECS.System.System
+ Aztecs.ECS.System: instance Control.Arrow.Arrow Aztecs.ECS.System.System
+ Aztecs.ECS.System: instance Control.Category.Category Aztecs.ECS.System.System
+ Aztecs.ECS.System: instance GHC.Base.Functor (Aztecs.ECS.System.System i)
+ Aztecs.ECS.System: map :: ArrowSystem q arr => q i a -> arr i [a]
+ Aztecs.ECS.System: mapSingle :: ArrowSystem q arr => q i a -> arr i a
+ Aztecs.ECS.System: mapSingleMaybe :: ArrowSystem q arr => q i a -> arr i (Maybe a)
+ Aztecs.ECS.System: map_ :: ArrowSystem q arr => q i o -> arr i ()
+ Aztecs.ECS.System: newtype System i o
+ Aztecs.ECS.System: queue :: ArrowSystem q arr => (i -> Access ()) -> arr i ()
+ Aztecs.ECS.System: single :: ArrowReaderSystem q arr => q i a -> arr i a
+ Aztecs.ECS.System.Class: class (Arrow arr) => ArrowSystem q arr | arr -> q
+ Aztecs.ECS.System.Class: filterMap :: ArrowSystem q arr => q i a -> QueryFilter -> arr i [a]
+ Aztecs.ECS.System.Class: map :: ArrowSystem q arr => q i a -> arr i [a]
+ Aztecs.ECS.System.Class: mapSingle :: ArrowSystem q arr => q i a -> arr i a
+ Aztecs.ECS.System.Class: mapSingleMaybe :: ArrowSystem q arr => q i a -> arr i (Maybe a)
+ Aztecs.ECS.System.Class: map_ :: ArrowSystem q arr => q i o -> arr i ()
+ Aztecs.ECS.System.Class: queue :: ArrowSystem q arr => (i -> Access ()) -> arr i ()
+ Aztecs.ECS.System.Dynamic: DynamicSystem :: (World -> i -> (o, View, Access ())) -> DynamicSystem i o
+ Aztecs.ECS.System.Dynamic: [runSystemDyn] :: DynamicSystem i o -> World -> i -> (o, View, Access ())
+ Aztecs.ECS.System.Dynamic: instance Aztecs.ECS.System.Dynamic.Class.ArrowDynamicSystem Aztecs.ECS.System.Dynamic.DynamicSystem
+ Aztecs.ECS.System.Dynamic: instance Aztecs.ECS.System.Dynamic.Reader.Class.ArrowDynamicReaderSystem Aztecs.ECS.System.Dynamic.DynamicSystem
+ Aztecs.ECS.System.Dynamic: instance Control.Arrow.Arrow Aztecs.ECS.System.Dynamic.DynamicSystem
+ Aztecs.ECS.System.Dynamic: instance Control.Category.Category Aztecs.ECS.System.Dynamic.DynamicSystem
+ Aztecs.ECS.System.Dynamic: instance GHC.Base.Functor (Aztecs.ECS.System.Dynamic.DynamicSystem i)
+ Aztecs.ECS.System.Dynamic: newtype DynamicSystem i o
+ Aztecs.ECS.System.Dynamic: raceDyn :: DynamicSystem i a -> DynamicSystem i b -> DynamicSystem i (a, b)
+ Aztecs.ECS.System.Dynamic.Class: class (ArrowDynamicReaderSystem arr) => ArrowDynamicSystem arr
+ Aztecs.ECS.System.Dynamic.Class: filterMapDyn :: ArrowDynamicSystem arr => Set ComponentID -> DynamicQuery i o -> (Node -> Bool) -> arr i [o]
+ Aztecs.ECS.System.Dynamic.Class: filterMapDyn' :: Set ComponentID -> DynamicQuery i o -> (Node -> Bool) -> DynamicSystem i [o]
+ Aztecs.ECS.System.Dynamic.Class: mapDyn :: ArrowDynamicSystem arr => Set ComponentID -> DynamicQuery i o -> arr i [o]
+ Aztecs.ECS.System.Dynamic.Class: mapDyn' :: Set ComponentID -> DynamicQuery i o -> DynamicSystem i [o]
+ Aztecs.ECS.System.Dynamic.Class: mapSingleDyn :: ArrowDynamicSystem arr => Set ComponentID -> DynamicQuery i o -> arr i o
+ Aztecs.ECS.System.Dynamic.Class: mapSingleDyn' :: Set ComponentID -> DynamicQuery i o -> DynamicSystem i o
+ Aztecs.ECS.System.Dynamic.Class: mapSingleMaybeDyn :: ArrowDynamicSystem arr => Set ComponentID -> DynamicQuery i o -> arr i (Maybe o)
+ Aztecs.ECS.System.Dynamic.Class: mapSingleMaybeDyn' :: Set ComponentID -> DynamicQuery i o -> DynamicSystem i (Maybe o)
+ Aztecs.ECS.System.Dynamic.Class: queueDyn :: ArrowDynamicSystem arr => (i -> Access ()) -> arr i ()
+ Aztecs.ECS.System.Dynamic.Class: queueDyn' :: (i -> Access ()) -> DynamicSystem i ()
+ Aztecs.ECS.System.Dynamic.Class: runArrowSystemDyn :: ArrowDynamicSystem arr => DynamicSystem i o -> arr i o
+ Aztecs.ECS.System.Dynamic.Class: type DynamicSystem i o = World -> i -> (o, View, Access ())
+ Aztecs.ECS.System.Dynamic.Reader: DynamicReaderSystem :: (World -> i -> o) -> DynamicReaderSystem i o
+ Aztecs.ECS.System.Dynamic.Reader: [runReaderSystemDyn] :: DynamicReaderSystem i o -> World -> i -> o
+ Aztecs.ECS.System.Dynamic.Reader: allDyn :: ArrowDynamicReaderSystem arr => Set ComponentID -> DynamicQueryReader i o -> arr i [o]
+ Aztecs.ECS.System.Dynamic.Reader: class (Arrow arr) => ArrowDynamicReaderSystem arr
+ Aztecs.ECS.System.Dynamic.Reader: filterDyn :: ArrowDynamicReaderSystem arr => Set ComponentID -> DynamicQueryReader i o -> (Node -> Bool) -> arr i [o]
+ Aztecs.ECS.System.Dynamic.Reader: instance Aztecs.ECS.System.Dynamic.Reader.Class.ArrowDynamicReaderSystem Aztecs.ECS.System.Dynamic.Reader.DynamicReaderSystem
+ Aztecs.ECS.System.Dynamic.Reader: instance Control.Arrow.Arrow Aztecs.ECS.System.Dynamic.Reader.DynamicReaderSystem
+ Aztecs.ECS.System.Dynamic.Reader: instance Control.Category.Category Aztecs.ECS.System.Dynamic.Reader.DynamicReaderSystem
+ Aztecs.ECS.System.Dynamic.Reader: instance GHC.Base.Functor (Aztecs.ECS.System.Dynamic.Reader.DynamicReaderSystem i)
+ Aztecs.ECS.System.Dynamic.Reader: newtype DynamicReaderSystem i o
+ Aztecs.ECS.System.Dynamic.Reader: raceDyn :: DynamicReaderSystem i a -> DynamicReaderSystem i b -> DynamicReaderSystem i (a, b)
+ Aztecs.ECS.System.Dynamic.Reader: singleDyn :: ArrowDynamicReaderSystem arr => Set ComponentID -> DynamicQueryReader () a -> arr () a
+ Aztecs.ECS.System.Dynamic.Reader.Class: allDyn :: ArrowDynamicReaderSystem arr => Set ComponentID -> DynamicQueryReader i o -> arr i [o]
+ Aztecs.ECS.System.Dynamic.Reader.Class: class (Arrow arr) => ArrowDynamicReaderSystem arr
+ Aztecs.ECS.System.Dynamic.Reader.Class: filterDyn :: ArrowDynamicReaderSystem arr => Set ComponentID -> DynamicQueryReader i o -> (Node -> Bool) -> arr i [o]
+ Aztecs.ECS.System.Dynamic.Reader.Class: singleDyn :: ArrowDynamicReaderSystem arr => Set ComponentID -> DynamicQueryReader () a -> arr () a
+ Aztecs.ECS.System.Reader: ReaderSystem :: (Components -> (DynamicReaderSystem i o, Set ComponentID, Components)) -> ReaderSystem i o
+ Aztecs.ECS.System.Reader: [runReaderSystem] :: ReaderSystem i o -> Components -> (DynamicReaderSystem i o, Set ComponentID, Components)
+ Aztecs.ECS.System.Reader: all :: ArrowReaderSystem q arr => q i a -> arr i [a]
+ Aztecs.ECS.System.Reader: filter :: ArrowReaderSystem q arr => q () a -> QueryFilter -> arr () [a]
+ Aztecs.ECS.System.Reader: filterMap :: ArrowSystem q arr => q i a -> QueryFilter -> arr i [a]
+ Aztecs.ECS.System.Reader: instance Aztecs.ECS.System.Reader.Class.ArrowReaderSystem Aztecs.ECS.Query.Reader.QueryReader Aztecs.ECS.System.Reader.ReaderSystem
+ Aztecs.ECS.System.Reader: instance Control.Arrow.Arrow Aztecs.ECS.System.Reader.ReaderSystem
+ Aztecs.ECS.System.Reader: instance Control.Category.Category Aztecs.ECS.System.Reader.ReaderSystem
+ Aztecs.ECS.System.Reader: instance GHC.Base.Functor (Aztecs.ECS.System.Reader.ReaderSystem i)
+ Aztecs.ECS.System.Reader: map :: ArrowSystem q arr => q i a -> arr i [a]
+ Aztecs.ECS.System.Reader: mapSingle :: ArrowSystem q arr => q i a -> arr i a
+ Aztecs.ECS.System.Reader: map_ :: ArrowSystem q arr => q i o -> arr i ()
+ Aztecs.ECS.System.Reader: newtype ReaderSystem i o
+ Aztecs.ECS.System.Reader: queue :: ArrowSystem q arr => (i -> Access ()) -> arr i ()
+ Aztecs.ECS.System.Reader: single :: ArrowReaderSystem q arr => q i a -> arr i a
+ Aztecs.ECS.System.Reader.Class: all :: ArrowReaderSystem q arr => q i a -> arr i [a]
+ Aztecs.ECS.System.Reader.Class: class (Arrow arr) => ArrowReaderSystem q arr | arr -> q
+ Aztecs.ECS.System.Reader.Class: filter :: ArrowReaderSystem q arr => q () a -> QueryFilter -> arr () [a]
+ Aztecs.ECS.System.Reader.Class: single :: ArrowReaderSystem q arr => q i a -> arr i a
+ Aztecs.ECS.View: View :: Map ArchetypeID Node -> View
+ Aztecs.ECS.View: [viewArchetypes] :: View -> Map ArchetypeID Node
+ Aztecs.ECS.View: allDyn :: i -> DynamicQuery i a -> View -> ([a], View)
+ Aztecs.ECS.View: filterView :: Set ComponentID -> (Node -> Bool) -> Archetypes -> View
+ Aztecs.ECS.View: instance GHC.Base.Monoid Aztecs.ECS.View.View
+ Aztecs.ECS.View: instance GHC.Base.Semigroup Aztecs.ECS.View.View
+ Aztecs.ECS.View: instance GHC.Show.Show Aztecs.ECS.View.View
+ Aztecs.ECS.View: newtype View
+ Aztecs.ECS.View: readAllDyn :: i -> DynamicQueryReader i a -> View -> [a]
+ Aztecs.ECS.View: singleDyn :: i -> DynamicQuery i a -> View -> (Maybe a, View)
+ Aztecs.ECS.View: unview :: View -> World -> World
+ Aztecs.ECS.View: view :: Set ComponentID -> Archetypes -> View
+ Aztecs.ECS.View: viewSingle :: Set ComponentID -> Archetypes -> Maybe View
+ Aztecs.ECS.World: World :: !Archetypes -> !Components -> !Map EntityID ArchetypeID -> !EntityID -> World
+ Aztecs.ECS.World: [archetypes] :: World -> !Archetypes
+ Aztecs.ECS.World: [components] :: World -> !Components
+ Aztecs.ECS.World: [entities] :: World -> !Map EntityID ArchetypeID
+ Aztecs.ECS.World: [nextEntityId] :: World -> !EntityID
+ Aztecs.ECS.World: data World
+ Aztecs.ECS.World: despawn :: EntityID -> World -> (Map ComponentID Dynamic, World)
+ Aztecs.ECS.World: empty :: World
+ Aztecs.ECS.World: insert :: forall a. (Component a, Typeable (StorageT a)) => EntityID -> a -> World -> World
+ Aztecs.ECS.World: insertWithId :: (Component a, Typeable (StorageT a)) => EntityID -> ComponentID -> a -> World -> World
+ Aztecs.ECS.World: instance Control.DeepSeq.NFData Aztecs.ECS.World.World
+ Aztecs.ECS.World: instance GHC.Generics.Generic Aztecs.ECS.World.World
+ Aztecs.ECS.World: instance GHC.Show.Show Aztecs.ECS.World.World
+ Aztecs.ECS.World: lookup :: forall a. Component a => EntityID -> World -> Maybe a
+ Aztecs.ECS.World: remove :: forall a. (Component a, Typeable (StorageT a)) => EntityID -> World -> (Maybe a, World)
+ Aztecs.ECS.World: removeWithId :: forall a. (Component a, Typeable (StorageT a)) => EntityID -> ComponentID -> World -> (Maybe a, World)
+ Aztecs.ECS.World: spawn :: Bundle -> World -> (EntityID, World)
+ Aztecs.ECS.World: spawnComponent :: forall a. (Component a, Typeable (StorageT a)) => a -> World -> (EntityID, World)
+ Aztecs.ECS.World: spawnEmpty :: World -> (EntityID, World)
+ Aztecs.ECS.World: spawnWithArchetypeId :: forall a. (Component a, Typeable (StorageT a)) => a -> ComponentID -> ArchetypeID -> World -> (EntityID, World)
+ Aztecs.ECS.World: spawnWithId :: forall a. (Component a, Typeable (StorageT a)) => ComponentID -> a -> World -> (EntityID, World)
+ Aztecs.ECS.World.Archetype: AnyStorage :: !Dynamic -> !Int -> Dynamic -> Dynamic -> Dynamic -> !Int -> Dynamic -> (Maybe Dynamic, Dynamic) -> !Int -> Dynamic -> (Maybe AnyStorage, Dynamic) -> !Dynamic -> [Int] -> !Dynamic -> () -> AnyStorage
+ Aztecs.ECS.World.Archetype: Archetype :: Map ComponentID AnyStorage -> Archetype
+ Aztecs.ECS.World.Archetype: Bundle :: (Components -> (Set ComponentID, Components, DynamicBundle)) -> Bundle
+ Aztecs.ECS.World.Archetype: DynamicBundle :: (EntityID -> Archetype -> Archetype) -> DynamicBundle
+ Aztecs.ECS.World.Archetype: [entitiesDyn] :: AnyStorage -> !Dynamic -> [Int]
+ Aztecs.ECS.World.Archetype: [insertDyn] :: AnyStorage -> !Int -> Dynamic -> Dynamic -> Dynamic
+ Aztecs.ECS.World.Archetype: [removeAny] :: AnyStorage -> !Int -> Dynamic -> (Maybe AnyStorage, Dynamic)
+ Aztecs.ECS.World.Archetype: [removeDyn] :: AnyStorage -> !Int -> Dynamic -> (Maybe Dynamic, Dynamic)
+ Aztecs.ECS.World.Archetype: [runDynamicBundle] :: DynamicBundle -> EntityID -> Archetype -> Archetype
+ Aztecs.ECS.World.Archetype: [storageDyn] :: AnyStorage -> !Dynamic
+ Aztecs.ECS.World.Archetype: [storageRnf] :: AnyStorage -> !Dynamic -> ()
+ Aztecs.ECS.World.Archetype: [storages] :: Archetype -> Map ComponentID AnyStorage
+ Aztecs.ECS.World.Archetype: [unBundle] :: Bundle -> Components -> (Set ComponentID, Components, DynamicBundle)
+ Aztecs.ECS.World.Archetype: all :: Component a => ComponentID -> Archetype -> [(EntityID, a)]
+ Aztecs.ECS.World.Archetype: allMaybe :: Component a => ComponentID -> Archetype -> [(EntityID, Maybe a)]
+ Aztecs.ECS.World.Archetype: anyStorage :: forall s a. Storage s a => s a -> AnyStorage
+ Aztecs.ECS.World.Archetype: bundle :: forall a. (Component a, Typeable (StorageT a)) => a -> Bundle
+ Aztecs.ECS.World.Archetype: data AnyStorage
+ Aztecs.ECS.World.Archetype: dynBundle :: (Component a, Typeable (StorageT a)) => ComponentID -> a -> DynamicBundle
+ Aztecs.ECS.World.Archetype: empty :: Archetype
+ Aztecs.ECS.World.Archetype: entities :: Archetype -> [EntityID]
+ Aztecs.ECS.World.Archetype: insertAscList :: forall a. Component a => ComponentID -> [(EntityID, a)] -> Archetype -> Archetype
+ Aztecs.ECS.World.Archetype: insertComponent :: forall a. Component a => EntityID -> ComponentID -> a -> Archetype -> Archetype
+ Aztecs.ECS.World.Archetype: instance Control.DeepSeq.NFData Aztecs.ECS.World.Archetype.AnyStorage
+ Aztecs.ECS.World.Archetype: instance Control.DeepSeq.NFData Aztecs.ECS.World.Archetype.Archetype
+ Aztecs.ECS.World.Archetype: instance GHC.Base.Monoid Aztecs.ECS.World.Archetype.Bundle
+ Aztecs.ECS.World.Archetype: instance GHC.Base.Monoid Aztecs.ECS.World.Archetype.DynamicBundle
+ Aztecs.ECS.World.Archetype: instance GHC.Base.Semigroup Aztecs.ECS.World.Archetype.Bundle
+ Aztecs.ECS.World.Archetype: instance GHC.Base.Semigroup Aztecs.ECS.World.Archetype.DynamicBundle
+ Aztecs.ECS.World.Archetype: instance GHC.Generics.Generic Aztecs.ECS.World.Archetype.Archetype
+ Aztecs.ECS.World.Archetype: instance GHC.Show.Show Aztecs.ECS.World.Archetype.AnyStorage
+ Aztecs.ECS.World.Archetype: instance GHC.Show.Show Aztecs.ECS.World.Archetype.Archetype
+ Aztecs.ECS.World.Archetype: lookupComponent :: forall a. Component a => EntityID -> ComponentID -> Archetype -> Maybe a
+ Aztecs.ECS.World.Archetype: lookupStorage :: Component a => ComponentID -> Archetype -> Maybe (StorageT a a)
+ Aztecs.ECS.World.Archetype: member :: ComponentID -> Archetype -> Bool
+ Aztecs.ECS.World.Archetype: newtype Archetype
+ Aztecs.ECS.World.Archetype: newtype Bundle
+ Aztecs.ECS.World.Archetype: newtype DynamicBundle
+ Aztecs.ECS.World.Archetype: remove :: EntityID -> Archetype -> (Map ComponentID Dynamic, Archetype)
+ Aztecs.ECS.World.Archetype: removeStorages :: EntityID -> Archetype -> (Map ComponentID AnyStorage, Archetype)
+ Aztecs.ECS.World.Archetype: runBundle :: Bundle -> Components -> EntityID -> Archetype -> (Components, Archetype)
+ Aztecs.ECS.World.Archetype: withAscList :: forall a. Component a => ComponentID -> [a] -> Archetype -> Archetype
+ Aztecs.ECS.World.Archetypes: ArchetypeID :: Int -> ArchetypeID
+ Aztecs.ECS.World.Archetypes: Archetypes :: !Map ArchetypeID Node -> !Map (Set ComponentID) ArchetypeID -> !ArchetypeID -> !Map ComponentID (Set ArchetypeID) -> Archetypes
+ Aztecs.ECS.World.Archetypes: Node :: !Set ComponentID -> !Archetype -> !Map ComponentID ArchetypeID -> !Map ComponentID ArchetypeID -> Node
+ Aztecs.ECS.World.Archetypes: [archetypeIds] :: Archetypes -> !Map (Set ComponentID) ArchetypeID
+ Aztecs.ECS.World.Archetypes: [componentIds] :: Archetypes -> !Map ComponentID (Set ArchetypeID)
+ Aztecs.ECS.World.Archetypes: [nextArchetypeId] :: Archetypes -> !ArchetypeID
+ Aztecs.ECS.World.Archetypes: [nodeAdd] :: Node -> !Map ComponentID ArchetypeID
+ Aztecs.ECS.World.Archetypes: [nodeArchetype] :: Node -> !Archetype
+ Aztecs.ECS.World.Archetypes: [nodeComponentIds] :: Node -> !Set ComponentID
+ Aztecs.ECS.World.Archetypes: [nodeRemove] :: Node -> !Map ComponentID ArchetypeID
+ Aztecs.ECS.World.Archetypes: [nodes] :: Archetypes -> !Map ArchetypeID Node
+ Aztecs.ECS.World.Archetypes: [unArchetypeId] :: ArchetypeID -> Int
+ Aztecs.ECS.World.Archetypes: adjustArchetype :: ArchetypeID -> (Archetype -> Archetype) -> Archetypes -> Archetypes
+ Aztecs.ECS.World.Archetypes: data Archetypes
+ Aztecs.ECS.World.Archetypes: data Node
+ Aztecs.ECS.World.Archetypes: empty :: Archetypes
+ Aztecs.ECS.World.Archetypes: findArchetypeIds :: Set ComponentID -> Archetypes -> Set ArchetypeID
+ Aztecs.ECS.World.Archetypes: insert :: (Component a, Typeable (StorageT a)) => EntityID -> ArchetypeID -> ComponentID -> a -> Archetypes -> (Maybe ArchetypeID, Archetypes)
+ Aztecs.ECS.World.Archetypes: insertArchetype :: Set ComponentID -> Node -> Archetypes -> (ArchetypeID, Archetypes)
+ Aztecs.ECS.World.Archetypes: instance Control.DeepSeq.NFData Aztecs.ECS.World.Archetypes.ArchetypeID
+ Aztecs.ECS.World.Archetypes: instance Control.DeepSeq.NFData Aztecs.ECS.World.Archetypes.Archetypes
+ Aztecs.ECS.World.Archetypes: instance Control.DeepSeq.NFData Aztecs.ECS.World.Archetypes.Node
+ Aztecs.ECS.World.Archetypes: instance GHC.Classes.Eq Aztecs.ECS.World.Archetypes.ArchetypeID
+ Aztecs.ECS.World.Archetypes: instance GHC.Classes.Ord Aztecs.ECS.World.Archetypes.ArchetypeID
+ Aztecs.ECS.World.Archetypes: instance GHC.Generics.Generic Aztecs.ECS.World.Archetypes.Archetypes
+ Aztecs.ECS.World.Archetypes: instance GHC.Generics.Generic Aztecs.ECS.World.Archetypes.Node
+ Aztecs.ECS.World.Archetypes: instance GHC.Show.Show Aztecs.ECS.World.Archetypes.ArchetypeID
+ Aztecs.ECS.World.Archetypes: instance GHC.Show.Show Aztecs.ECS.World.Archetypes.Archetypes
+ Aztecs.ECS.World.Archetypes: instance GHC.Show.Show Aztecs.ECS.World.Archetypes.Node
+ Aztecs.ECS.World.Archetypes: lookup :: Set ComponentID -> Archetypes -> Map ArchetypeID Node
+ Aztecs.ECS.World.Archetypes: lookupArchetypeId :: Set ComponentID -> Archetypes -> Maybe ArchetypeID
+ Aztecs.ECS.World.Archetypes: lookupNode :: ArchetypeID -> Archetypes -> Maybe Node
+ Aztecs.ECS.World.Archetypes: map :: Set ComponentID -> (Archetype -> (a, Archetype)) -> Archetypes -> ([a], Archetypes)
+ Aztecs.ECS.World.Archetypes: newtype ArchetypeID
+ Aztecs.ECS.World.Archetypes: remove :: (Component a, Typeable (StorageT a)) => EntityID -> ArchetypeID -> ComponentID -> Archetypes -> (Maybe (a, ArchetypeID), Archetypes)
+ Aztecs.ECS.World.Components: ComponentID :: Int -> ComponentID
+ Aztecs.ECS.World.Components: Components :: !Map TypeRep ComponentID -> !ComponentID -> Components
+ Aztecs.ECS.World.Components: [componentIds] :: Components -> !Map TypeRep ComponentID
+ Aztecs.ECS.World.Components: [nextComponentId] :: Components -> !ComponentID
+ Aztecs.ECS.World.Components: [unComponentId] :: ComponentID -> Int
+ Aztecs.ECS.World.Components: data Components
+ Aztecs.ECS.World.Components: empty :: Components
+ Aztecs.ECS.World.Components: insert :: forall a. Component a => Components -> (ComponentID, Components)
+ Aztecs.ECS.World.Components: insert' :: forall c. Component c => Components -> (ComponentID, Components)
+ Aztecs.ECS.World.Components: instance Control.DeepSeq.NFData Aztecs.ECS.World.Components.Components
+ Aztecs.ECS.World.Components: instance GHC.Generics.Generic Aztecs.ECS.World.Components.Components
+ Aztecs.ECS.World.Components: instance GHC.Show.Show Aztecs.ECS.World.Components.Components
+ Aztecs.ECS.World.Components: lookup :: forall a. Typeable a => Components -> Maybe ComponentID
+ Aztecs.ECS.World.Components: newtype ComponentID
+ Aztecs.ECS.World.Storage: all :: Storage s a => s a -> [(Int, a)]
+ Aztecs.ECS.World.Storage: class (Typeable (s a), NFData (s a), Typeable a) => Storage s a
+ Aztecs.ECS.World.Storage: fromAscList :: Storage s a => [(Int, a)] -> s a
+ Aztecs.ECS.World.Storage: insert :: Storage s a => Int -> a -> s a -> s a
+ Aztecs.ECS.World.Storage: instance (Data.Typeable.Internal.Typeable a, Control.DeepSeq.NFData a) => Aztecs.ECS.World.Storage.Storage Data.IntMap.Internal.IntMap a
+ Aztecs.ECS.World.Storage: lookup :: Storage s a => Int -> s a -> Maybe a
+ Aztecs.ECS.World.Storage: remove :: Storage s a => Int -> s a -> (Maybe a, s a)
+ Aztecs.ECS.World.Storage: singleton :: Storage s a => Int -> a -> s a
+ Aztecs.Hierarchy: ChildState :: Set EntityID -> ChildState
+ Aztecs.Hierarchy: Children :: Set EntityID -> Children
+ Aztecs.Hierarchy: Node :: EntityID -> a -> [Hierarchy a] -> Hierarchy a
+ Aztecs.Hierarchy: Parent :: EntityID -> Parent
+ Aztecs.Hierarchy: ParentState :: EntityID -> ParentState
+ Aztecs.Hierarchy: [nodeChildren] :: Hierarchy a -> [Hierarchy a]
+ Aztecs.Hierarchy: [nodeEntityId] :: Hierarchy a -> EntityID
+ Aztecs.Hierarchy: [nodeEntity] :: Hierarchy a -> a
+ Aztecs.Hierarchy: [unChildState] :: ChildState -> Set EntityID
+ Aztecs.Hierarchy: [unChildren] :: Children -> Set EntityID
+ Aztecs.Hierarchy: [unParentState] :: ParentState -> EntityID
+ Aztecs.Hierarchy: [unParent] :: Parent -> EntityID
+ Aztecs.Hierarchy: data Hierarchy a
+ Aztecs.Hierarchy: hierarchies :: (ArrowQueryReader q, ArrowReaderSystem q arr) => q i a -> arr i [[Hierarchy a]]
+ Aztecs.Hierarchy: hierarchy :: (ArrowQueryReader q, ArrowReaderSystem q arr) => EntityID -> q i a -> arr i [Hierarchy a]
+ Aztecs.Hierarchy: instance Aztecs.ECS.Component.Component Aztecs.Hierarchy.ChildState
+ Aztecs.Hierarchy: instance Aztecs.ECS.Component.Component Aztecs.Hierarchy.Children
+ Aztecs.Hierarchy: instance Aztecs.ECS.Component.Component Aztecs.Hierarchy.Parent
+ Aztecs.Hierarchy: instance Aztecs.ECS.Component.Component Aztecs.Hierarchy.ParentState
+ Aztecs.Hierarchy: instance Control.DeepSeq.NFData Aztecs.Hierarchy.ChildState
+ Aztecs.Hierarchy: instance Control.DeepSeq.NFData Aztecs.Hierarchy.Children
+ Aztecs.Hierarchy: instance Control.DeepSeq.NFData Aztecs.Hierarchy.Parent
+ Aztecs.Hierarchy: instance Control.DeepSeq.NFData Aztecs.Hierarchy.ParentState
+ Aztecs.Hierarchy: instance GHC.Base.Monoid Aztecs.Hierarchy.Children
+ Aztecs.Hierarchy: instance GHC.Base.Semigroup Aztecs.Hierarchy.Children
+ Aztecs.Hierarchy: instance GHC.Classes.Eq Aztecs.Hierarchy.Children
+ Aztecs.Hierarchy: instance GHC.Classes.Eq Aztecs.Hierarchy.Parent
+ Aztecs.Hierarchy: instance GHC.Classes.Ord Aztecs.Hierarchy.Children
+ Aztecs.Hierarchy: instance GHC.Classes.Ord Aztecs.Hierarchy.Parent
+ Aztecs.Hierarchy: instance GHC.Generics.Generic Aztecs.Hierarchy.ChildState
+ Aztecs.Hierarchy: instance GHC.Generics.Generic Aztecs.Hierarchy.Children
+ Aztecs.Hierarchy: instance GHC.Generics.Generic Aztecs.Hierarchy.Parent
+ Aztecs.Hierarchy: instance GHC.Generics.Generic Aztecs.Hierarchy.ParentState
+ Aztecs.Hierarchy: instance GHC.Show.Show Aztecs.Hierarchy.ChildState
+ Aztecs.Hierarchy: instance GHC.Show.Show Aztecs.Hierarchy.Children
+ Aztecs.Hierarchy: instance GHC.Show.Show Aztecs.Hierarchy.Parent
+ Aztecs.Hierarchy: instance GHC.Show.Show Aztecs.Hierarchy.ParentState
+ Aztecs.Hierarchy: newtype ChildState
+ Aztecs.Hierarchy: newtype Children
+ Aztecs.Hierarchy: newtype Parent
+ Aztecs.Hierarchy: newtype ParentState
+ Aztecs.Hierarchy: update :: (ArrowQueryReader qr, ArrowQuery q, ArrowReaderSystem qr arr, ArrowSystem q arr) => arr () ()
+ Aztecs.Input: ButtonExtra :: !Int -> MouseButton
+ Aztecs.Input: ButtonLeft :: MouseButton
+ Aztecs.Input: ButtonMiddle :: MouseButton
+ Aztecs.Input: ButtonRight :: MouseButton
+ Aztecs.Input: ButtonX1 :: MouseButton
+ Aztecs.Input: ButtonX2 :: MouseButton
+ Aztecs.Input: Key0 :: Key
+ Aztecs.Input: Key1 :: Key
+ Aztecs.Input: Key2 :: Key
+ Aztecs.Input: Key3 :: Key
+ Aztecs.Input: Key4 :: Key
+ Aztecs.Input: Key5 :: Key
+ Aztecs.Input: Key6 :: Key
+ Aztecs.Input: Key7 :: Key
+ Aztecs.Input: Key8 :: Key
+ Aztecs.Input: Key9 :: Key
+ Aztecs.Input: KeyA :: Key
+ Aztecs.Input: KeyAlt :: Key
+ Aztecs.Input: KeyB :: Key
+ Aztecs.Input: KeyBackslash :: Key
+ Aztecs.Input: KeyBackspace :: Key
+ Aztecs.Input: KeyBracketLeft :: Key
+ Aztecs.Input: KeyBracketRight :: Key
+ Aztecs.Input: KeyC :: Key
+ Aztecs.Input: KeyCapsLock :: Key
+ Aztecs.Input: KeyComma :: Key
+ Aztecs.Input: KeyCtrl :: Key
+ Aztecs.Input: KeyD :: Key
+ Aztecs.Input: KeyDelete :: Key
+ Aztecs.Input: KeyDown :: Key
+ Aztecs.Input: KeyE :: Key
+ Aztecs.Input: KeyEnd :: Key
+ Aztecs.Input: KeyEnter :: Key
+ Aztecs.Input: KeyEquals :: Key
+ Aztecs.Input: KeyEscape :: Key
+ Aztecs.Input: KeyF :: Key
+ Aztecs.Input: KeyF1 :: Key
+ Aztecs.Input: KeyF10 :: Key
+ Aztecs.Input: KeyF11 :: Key
+ Aztecs.Input: KeyF12 :: Key
+ Aztecs.Input: KeyF2 :: Key
+ Aztecs.Input: KeyF3 :: Key
+ Aztecs.Input: KeyF4 :: Key
+ Aztecs.Input: KeyF5 :: Key
+ Aztecs.Input: KeyF6 :: Key
+ Aztecs.Input: KeyF7 :: Key
+ Aztecs.Input: KeyF8 :: Key
+ Aztecs.Input: KeyF9 :: Key
+ Aztecs.Input: KeyG :: Key
+ Aztecs.Input: KeyH :: Key
+ Aztecs.Input: KeyHome :: Key
+ Aztecs.Input: KeyI :: Key
+ Aztecs.Input: KeyInsert :: Key
+ Aztecs.Input: KeyJ :: Key
+ Aztecs.Input: KeyK :: Key
+ Aztecs.Input: KeyL :: Key
+ Aztecs.Input: KeyLeft :: Key
+ Aztecs.Input: KeyM :: Key
+ Aztecs.Input: KeyMenu :: Key
+ Aztecs.Input: KeyMinus :: Key
+ Aztecs.Input: KeyN :: Key
+ Aztecs.Input: KeyNumLock :: Key
+ Aztecs.Input: KeyNumpad0 :: Key
+ Aztecs.Input: KeyNumpad1 :: Key
+ Aztecs.Input: KeyNumpad2 :: Key
+ Aztecs.Input: KeyNumpad3 :: Key
+ Aztecs.Input: KeyNumpad4 :: Key
+ Aztecs.Input: KeyNumpad5 :: Key
+ Aztecs.Input: KeyNumpad6 :: Key
+ Aztecs.Input: KeyNumpad7 :: Key
+ Aztecs.Input: KeyNumpad8 :: Key
+ Aztecs.Input: KeyNumpad9 :: Key
+ Aztecs.Input: KeyNumpadDivide :: Key
+ Aztecs.Input: KeyNumpadEnter :: Key
+ Aztecs.Input: KeyNumpadMinus :: Key
+ Aztecs.Input: KeyNumpadMultiply :: Key
+ Aztecs.Input: KeyNumpadPeriod :: Key
+ Aztecs.Input: KeyNumpadPlus :: Key
+ Aztecs.Input: KeyO :: Key
+ Aztecs.Input: KeyP :: Key
+ Aztecs.Input: KeyPageDown :: Key
+ Aztecs.Input: KeyPageUp :: Key
+ Aztecs.Input: KeyPeriod :: Key
+ Aztecs.Input: KeyQ :: Key
+ Aztecs.Input: KeyR :: Key
+ Aztecs.Input: KeyRight :: Key
+ Aztecs.Input: KeyS :: Key
+ Aztecs.Input: KeySemicolon :: Key
+ Aztecs.Input: KeyShift :: Key
+ Aztecs.Input: KeySlash :: Key
+ Aztecs.Input: KeySpace :: Key
+ Aztecs.Input: KeySuper :: Key
+ Aztecs.Input: KeyT :: Key
+ Aztecs.Input: KeyTab :: Key
+ Aztecs.Input: KeyU :: Key
+ Aztecs.Input: KeyUp :: Key
+ Aztecs.Input: KeyV :: Key
+ Aztecs.Input: KeyW :: Key
+ Aztecs.Input: KeyX :: Key
+ Aztecs.Input: KeyY :: Key
+ Aztecs.Input: KeyZ :: Key
+ Aztecs.Input: KeyboardInput :: !Map Key InputMotion -> !Set Key -> KeyboardInput
+ Aztecs.Input: MouseInput :: !Point V2 Int -> !V2 Int -> !Map MouseButton InputMotion -> MouseInput
+ Aztecs.Input: Pressed :: InputMotion
+ Aztecs.Input: Released :: InputMotion
+ Aztecs.Input: [keyboardEvents] :: KeyboardInput -> !Map Key InputMotion
+ Aztecs.Input: [keyboardPressed] :: KeyboardInput -> !Set Key
+ Aztecs.Input: [mouseButtons] :: MouseInput -> !Map MouseButton InputMotion
+ Aztecs.Input: [mouseOffset] :: MouseInput -> !V2 Int
+ Aztecs.Input: [mousePosition] :: MouseInput -> !Point V2 Int
+ Aztecs.Input: data InputMotion
+ Aztecs.Input: data Key
+ Aztecs.Input: data KeyboardInput
+ Aztecs.Input: data MouseButton
+ Aztecs.Input: data MouseInput
+ Aztecs.Input: handleKeyboardEvent :: Key -> InputMotion -> KeyboardInput -> KeyboardInput
+ Aztecs.Input: handleMouseMotion :: V2 Int -> MouseInput -> MouseInput
+ Aztecs.Input: instance Aztecs.ECS.Component.Component Aztecs.Input.KeyboardInput
+ Aztecs.Input: instance Aztecs.ECS.Component.Component Aztecs.Input.MouseInput
+ Aztecs.Input: instance Control.DeepSeq.NFData Aztecs.Input.InputMotion
+ Aztecs.Input: instance Control.DeepSeq.NFData Aztecs.Input.Key
+ Aztecs.Input: instance Control.DeepSeq.NFData Aztecs.Input.KeyboardInput
+ Aztecs.Input: instance Control.DeepSeq.NFData Aztecs.Input.MouseButton
+ Aztecs.Input: instance Control.DeepSeq.NFData Aztecs.Input.MouseInput
+ Aztecs.Input: instance GHC.Classes.Eq Aztecs.Input.InputMotion
+ Aztecs.Input: instance GHC.Classes.Eq Aztecs.Input.Key
+ Aztecs.Input: instance GHC.Classes.Eq Aztecs.Input.MouseButton
+ Aztecs.Input: instance GHC.Classes.Ord Aztecs.Input.Key
+ Aztecs.Input: instance GHC.Classes.Ord Aztecs.Input.MouseButton
+ Aztecs.Input: instance GHC.Enum.Bounded Aztecs.Input.Key
+ Aztecs.Input: instance GHC.Enum.Enum Aztecs.Input.Key
+ Aztecs.Input: instance GHC.Generics.Generic Aztecs.Input.InputMotion
+ Aztecs.Input: instance GHC.Generics.Generic Aztecs.Input.Key
+ Aztecs.Input: instance GHC.Generics.Generic Aztecs.Input.KeyboardInput
+ Aztecs.Input: instance GHC.Generics.Generic Aztecs.Input.MouseButton
+ Aztecs.Input: instance GHC.Generics.Generic Aztecs.Input.MouseInput
+ Aztecs.Input: instance GHC.Show.Show Aztecs.Input.InputMotion
+ Aztecs.Input: instance GHC.Show.Show Aztecs.Input.Key
+ Aztecs.Input: instance GHC.Show.Show Aztecs.Input.KeyboardInput
+ Aztecs.Input: instance GHC.Show.Show Aztecs.Input.MouseButton
+ Aztecs.Input: instance GHC.Show.Show Aztecs.Input.MouseInput
+ Aztecs.Input: isKeyPressed :: Key -> KeyboardInput -> Bool
+ Aztecs.Input: keyboardInput :: KeyboardInput
+ Aztecs.Input: mouseInput :: MouseInput
+ Aztecs.Input: wasKeyPressed :: Key -> KeyboardInput -> Bool
+ Aztecs.Input: wasKeyReleased :: Key -> KeyboardInput -> Bool
+ Aztecs.Time: Time :: Word32 -> Time
+ Aztecs.Time: [elapsedMS] :: Time -> Word32
+ Aztecs.Time: instance Aztecs.ECS.Component.Component Aztecs.Time.Time
+ Aztecs.Time: instance Control.DeepSeq.NFData Aztecs.Time.Time
+ Aztecs.Time: instance GHC.Classes.Eq Aztecs.Time.Time
+ Aztecs.Time: instance GHC.Classes.Ord Aztecs.Time.Time
+ Aztecs.Time: instance GHC.Generics.Generic Aztecs.Time.Time
+ Aztecs.Time: instance GHC.Num.Num Aztecs.Time.Time
+ Aztecs.Time: instance GHC.Show.Show Aztecs.Time.Time
+ Aztecs.Time: newtype Time
+ Aztecs.Transform: Size :: V2 Int -> Size
+ Aztecs.Transform: Transform :: !V2 Int -> !Float -> !V2 Int -> Transform
+ Aztecs.Transform: [transformPosition] :: Transform -> !V2 Int
+ Aztecs.Transform: [transformRotation] :: Transform -> !Float
+ Aztecs.Transform: [transformScale] :: Transform -> !V2 Int
+ Aztecs.Transform: [unSize] :: Size -> V2 Int
+ Aztecs.Transform: data Transform
+ Aztecs.Transform: instance Aztecs.ECS.Component.Component Aztecs.Transform.Size
+ Aztecs.Transform: instance Aztecs.ECS.Component.Component Aztecs.Transform.Transform
+ Aztecs.Transform: instance Control.DeepSeq.NFData Aztecs.Transform.Size
+ Aztecs.Transform: instance Control.DeepSeq.NFData Aztecs.Transform.Transform
+ Aztecs.Transform: instance GHC.Classes.Eq Aztecs.Transform.Transform
+ Aztecs.Transform: instance GHC.Generics.Generic Aztecs.Transform.Size
+ Aztecs.Transform: instance GHC.Generics.Generic Aztecs.Transform.Transform
+ Aztecs.Transform: instance GHC.Show.Show Aztecs.Transform.Transform
+ Aztecs.Transform: newtype Size
+ Aztecs.Transform: transform :: Transform
+ Aztecs.Window: Window :: !String -> Window
+ Aztecs.Window: [windowTitle] :: Window -> !String
+ Aztecs.Window: data Window
+ Aztecs.Window: instance Aztecs.ECS.Component.Component Aztecs.Window.Window
+ Aztecs.Window: instance Control.DeepSeq.NFData Aztecs.Window.Window
+ Aztecs.Window: instance GHC.Generics.Generic Aztecs.Window.Window
+ Aztecs.Window: instance GHC.Show.Show Aztecs.Window.Window
Files
- aztecs.cabal +44/−32
- bench/Iter.hs +20/−14
- examples/ECS.hs +0/−36
- src/Aztecs.hs +84/−0
- src/Aztecs/Asset.hs +154/−0
- src/Aztecs/Camera.hs +56/−0
- src/Aztecs/ECS.hs +94/−0
- src/Aztecs/ECS/Access.hs +51/−0
- src/Aztecs/ECS/Access/Class.hs +32/−0
- src/Aztecs/ECS/Component.hs +24/−0
- src/Aztecs/ECS/Entity.hs +11/−0
- src/Aztecs/ECS/Query.hs +138/−0
- src/Aztecs/ECS/Query/Class.hs +8/−0
- src/Aztecs/ECS/Query/Dynamic.hs +77/−0
- src/Aztecs/ECS/Query/Dynamic/Class.hs +7/−0
- src/Aztecs/ECS/Query/Dynamic/Reader.hs +69/−0
- src/Aztecs/ECS/Query/Dynamic/Reader/Class.hs +16/−0
- src/Aztecs/ECS/Query/Reader.hs +114/−0
- src/Aztecs/ECS/Query/Reader/Class.hs +16/−0
- src/Aztecs/ECS/Schedule.hs +100/−0
- src/Aztecs/ECS/System.hs +85/−0
- src/Aztecs/ECS/System/Class.hs +28/−0
- src/Aztecs/ECS/System/Dynamic.hs +50/−0
- src/Aztecs/ECS/System/Dynamic/Class.hs +80/−0
- src/Aztecs/ECS/System/Dynamic/Reader.hs +60/−0
- src/Aztecs/ECS/System/Dynamic/Reader/Class.hs +21/−0
- src/Aztecs/ECS/System/Reader.hs +74/−0
- src/Aztecs/ECS/System/Reader/Class.hs +26/−0
- src/Aztecs/ECS/View.hs +96/−0
- src/Aztecs/ECS/World.hs +245/−0
- src/Aztecs/ECS/World/Archetype.hs +218/−0
- src/Aztecs/ECS/World/Archetypes.hs +271/−0
- src/Aztecs/ECS/World/Components.hs +60/−0
- src/Aztecs/ECS/World/Storage.hs +38/−0
- src/Aztecs/Hierarchy.hs +175/−0
- src/Aztecs/Input.hs +205/−0
- src/Aztecs/Time.hs +17/−0
- src/Aztecs/Transform.hs +26/−0
- src/Aztecs/Window.hs +17/−0
- src/Data/Aztecs.hs +0/−81
- src/Data/Aztecs/Access.hs +0/−69
- src/Data/Aztecs/Component.hs +0/−20
- src/Data/Aztecs/Entity.hs +0/−5
- src/Data/Aztecs/Query.hs +0/−318
- src/Data/Aztecs/Schedule.hs +0/−70
- src/Data/Aztecs/Storage.hs +0/−37
- src/Data/Aztecs/System.hs +0/−214
- src/Data/Aztecs/View.hs +0/−70
- src/Data/Aztecs/World.hs +0/−279
- src/Data/Aztecs/World/Archetype.hs +0/−207
- src/Data/Aztecs/World/Archetypes.hs +0/−123
- src/Data/Aztecs/World/Components.hs +0/−56
- test/Main.hs +26/−11
aztecs.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: aztecs-version: 0.5.0.1+version: 0.6.0 license: BSD-3-Clause license-file: LICENSE maintainer: matt@hunzinger.me@@ -19,45 +19,54 @@ type: git location: https://github.com/matthunz/aztecs.git -flag examples- description: Build examples- default: False- manual: True- library exposed-modules:- Data.Aztecs- Data.Aztecs.Access- Data.Aztecs.Component- Data.Aztecs.Entity- Data.Aztecs.Query- Data.Aztecs.Schedule- Data.Aztecs.Storage- Data.Aztecs.System- Data.Aztecs.View- Data.Aztecs.World- Data.Aztecs.World.Archetype- Data.Aztecs.World.Archetypes- Data.Aztecs.World.Components+ Aztecs+ Aztecs.ECS+ Aztecs.ECS.Access+ Aztecs.ECS.Access.Class+ Aztecs.ECS.Component+ Aztecs.ECS.Entity+ Aztecs.ECS.Query+ Aztecs.ECS.Query.Class+ Aztecs.ECS.Query.Dynamic+ Aztecs.ECS.Query.Dynamic.Class+ Aztecs.ECS.Query.Dynamic.Reader+ Aztecs.ECS.Query.Dynamic.Reader.Class+ Aztecs.ECS.Query.Reader+ Aztecs.ECS.Query.Reader.Class+ Aztecs.ECS.Schedule+ Aztecs.ECS.System+ Aztecs.ECS.System.Class+ Aztecs.ECS.System.Dynamic+ Aztecs.ECS.System.Dynamic.Class+ Aztecs.ECS.System.Dynamic.Reader+ Aztecs.ECS.System.Dynamic.Reader.Class+ Aztecs.ECS.System.Reader+ Aztecs.ECS.System.Reader.Class+ Aztecs.ECS.View+ Aztecs.ECS.World+ Aztecs.ECS.World.Archetype+ Aztecs.ECS.World.Archetypes+ Aztecs.ECS.World.Components+ Aztecs.ECS.World.Storage+ Aztecs.Asset+ Aztecs.Camera+ Aztecs.Hierarchy+ Aztecs.Input+ Aztecs.Time+ Aztecs.Transform+ Aztecs.Window hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall build-depends: base >=4.6 && <5, containers >=0.6,+ deepseq >=1,+ linear >=1, mtl >=2,- parallel-io >=0.3.5--executable ecs- main-is: ECS.hs- hs-source-dirs: examples- default-language: Haskell2010- ghc-options: -Wall- if flag(examples)- build-depends: base, aztecs- else- buildable: False-+ parallel >=3, test-suite aztecs-test type: exitcode-stdio-1.0@@ -68,6 +77,8 @@ build-depends: base >=4.6 && <5, aztecs,+ containers >=0.6,+ deepseq >=1, hspec >=2, QuickCheck >=2 @@ -80,4 +91,5 @@ build-depends: base >=4.6 && <5, aztecs,- criterion >=1+ criterion >=1,+ deepseq >=1
bench/Iter.hs view
@@ -1,31 +1,37 @@ {-# LANGUAGE Arrows #-} {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} +import Aztecs.ECS+import qualified Aztecs.ECS.Query as Q+import qualified Aztecs.ECS.System as S+import qualified Aztecs.ECS.World as W+import Control.DeepSeq+import Control.Monad (void) import Criterion.Main-import Data.Aztecs-import qualified Data.Aztecs.Query as Q-import qualified Data.Aztecs.System as S-import qualified Data.Aztecs.World as W+import GHC.Generics (Generic) -newtype Position = Position Int deriving (Show)+newtype Position = Position Int deriving (Show, Generic, NFData) instance Component Position -newtype Velocity = Velocity Int deriving (Show)+newtype Velocity = Velocity Int deriving (Show, Generic, NFData) instance Component Velocity run :: World -> IO () run w = do let s =- const ()- <$> S.map- ( proc () -> do- Velocity v <- Q.fetch -< ()- Position p <- Q.fetch -< ()- Q.set -< Position $ p + v- )- !_ <- S.runSystemWithWorld s w+ void+ ( S.map+ ( proc () -> do+ Velocity v <- Q.fetch -< ()+ Position p <- Q.fetch -< ()+ Q.set -< Position $ p + v+ )+ )+ !_ <- runSchedule (system s) w () return () main :: IO ()
− examples/ECS.hs
@@ -1,36 +0,0 @@-{-# LANGUAGE Arrows #-}--module Main where--import Control.Arrow ((>>>))-import Data.Aztecs-import qualified Data.Aztecs.Access as A-import qualified Data.Aztecs.Query as Q-import qualified Data.Aztecs.System as S--newtype Position = Position Int deriving (Show)--instance Component Position--newtype Velocity = Velocity Int deriving (Show)--instance Component Velocity--setup :: System () ()-setup = S.queue . const . A.spawn_ $ bundle (Position 0) <> bundle (Velocity 1)--move :: System () ()-move =- S.map- ( proc () -> do- Velocity v <- Q.fetch -< ()- Position p <- Q.fetch -< ()- Q.set -< Position $ p + v- )- >>> S.task print--app :: Schedule IO () ()-app = schedule setup >>> forever (schedule move)--main :: IO ()-main = runSchedule_ $ app
+ src/Aztecs.hs view
@@ -0,0 +1,84 @@+-- | Aztecs is a type-safe and friendly ECS for games and more.+--+-- An ECS is a modern approach to organizing your application state as a database,+-- providing patterns for data-oriented design and parallel processing.+--+-- The ECS architecture is composed of three main concepts:+--+-- === Entities+-- An entity is an object comprised of zero or more components.+-- In Aztecs, entities are represented by their `EntityID`, a unique identifier.+--+-- === Components+-- A `Component` holds the data for a particular aspect of an entity.+-- For example, a zombie entity might have a @Health@ and a @Transform@ component.+--+-- > newtype Position = Position Int deriving (Show)+-- > instance Component Position+-- >+-- > newtype Velocity = Velocity Int deriving (Show)+-- > instance Component Velocity+--+-- === Systems+-- A `System` is a pipeline that processes entities and their components.+-- Systems in Aztecs either run in sequence or in parallel automatically based on the components they access.+--+-- Systems can access game state in two ways:+--+-- ==== Access+-- An `Access` can be queued for full access to the `World`, after a system is complete.+-- `Access` allows for spawning, inserting, and removing components.+--+-- > setup :: System () ()+-- > setup = S.queue . const . A.spawn_ $ bundle (Position 0) <> bundle (Velocity 1)+--+-- ==== Queries+-- A `Query` can read and write matching components.+--+-- > move :: System () ()+-- > move =+-- > S.map+-- > ( proc () -> do+-- > Velocity v <- Q.fetch -< ()+-- > Position p <- Q.fetch -< ()+-- > Q.set -< Position $ p + v+-- > )+-- > >>> S.run print+--+-- Finally, systems can be run on a `World` to produce a result.+--+-- > main :: IO ()+-- > main = runSystem_ $ setup >>> S.forever move+module Aztecs+ ( module Aztecs.ECS,+ asset,+ load,+ Camera (..),+ CameraTarget (..),+ Transform (..),+ transform,+ Key (..),+ KeyboardInput (..),+ isKeyPressed,+ wasKeyPressed,+ wasKeyReleased,+ MouseInput (..),+ Time (..),+ Window (..),+ )+where++import Aztecs.Asset (asset, load)+import Aztecs.Camera+import Aztecs.ECS+import Aztecs.Input+ ( Key (..),+ KeyboardInput (..),+ MouseInput (..),+ isKeyPressed,+ wasKeyPressed,+ wasKeyReleased,+ )+import Aztecs.Time+import Aztecs.Transform (Transform (..), transform)+import Aztecs.Window
+ src/Aztecs/Asset.hs view
@@ -0,0 +1,154 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE Arrows #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.Asset+ ( AssetId (..),+ AssetServer (..),+ empty,+ Asset (..),+ Handle (..),+ MonadAssetLoader (..),+ AssetLoader,+ AssetLoaderT (..),+ load,+ setup,+ loadQuery,+ loadAssets,+ lookupAsset,+ )+where++import Aztecs.ECS+import qualified Aztecs.ECS.Access as A+import Aztecs.ECS.Query (ArrowQuery)+import qualified Aztecs.ECS.Query as Q+import Aztecs.ECS.Query.Reader (QueryReader)+import Aztecs.ECS.System (ArrowSystem)+import qualified Aztecs.ECS.System as S+import Control.Arrow (returnA)+import Control.Concurrent (forkIO)+import Control.DeepSeq+import Control.Monad.Identity (Identity)+import Control.Monad.State.Strict (MonadState (..), StateT, runState)+import Data.Data (Typeable)+import Data.Foldable (foldrM)+import Data.IORef (IORef, newIORef, readIORef, writeIORef)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import GHC.Generics (Generic)++newtype AssetId = AssetId {unAssetId :: Int}+ deriving (Eq, Ord, Show)++data AssetServer a = AssetServer+ { assetServerAssets :: !(Map AssetId a),+ loadingAssets :: !(Map AssetId (Either (IO (IORef (Maybe a))) (IORef (Maybe a)))),+ nextAssetId :: !AssetId+ }+ deriving (Generic)++instance (Typeable a) => Component (AssetServer a)++instance NFData (AssetServer a) where+ rnf = rwhnf++empty :: AssetServer a+empty =+ AssetServer+ { assetServerAssets = Map.empty,+ loadingAssets = Map.empty,+ nextAssetId = AssetId 0+ }++class (Typeable a) => Asset a where+ type AssetConfig a++ loadAsset :: FilePath -> AssetConfig a -> IO a++newtype Handle a = Handle {handleId :: AssetId}+ deriving (Eq, Ord, Show)++instance NFData (Handle a) where+ rnf = rwhnf++class MonadAssetLoader a m | m -> a where+ asset :: FilePath -> AssetConfig a -> m (Handle a)++type AssetLoader a o = AssetLoaderT a Identity o++newtype AssetLoaderT a m o = AssetLoaderT {unAssetLoader :: StateT (AssetServer a) m o}+ deriving newtype (Functor, Applicative, Monad)++instance (Monad m, Asset a) => MonadAssetLoader a (AssetLoaderT a m) where+ asset path cfg = AssetLoaderT $ do+ server <- get+ let assetId = nextAssetId server+ go = do+ v <- newIORef Nothing+ _ <- forkIO $ do+ a <- loadAsset path cfg+ writeIORef v (Just a)+ return v+ put $+ server+ { loadingAssets = Map.insert assetId (Left go) (loadingAssets server),+ nextAssetId = AssetId (unAssetId assetId + 1)+ }+ return $ Handle assetId++loadQuery :: (Asset a, ArrowQuery arr) => AssetLoader a o -> arr () o+loadQuery a = proc () -> do+ assetServer <- Q.fetch -< ()+ let (o, assetServer') = runState (unAssetLoader a) assetServer+ Q.set -< assetServer'+ returnA -< o++load :: (ArrowSystem Query arr, Asset a) => AssetLoader a o -> arr () o+load a = S.mapSingle $ loadQuery a++lookupAsset :: Handle a -> AssetServer a -> Maybe a+lookupAsset h server = Map.lookup (handleId h) (assetServerAssets server)++loadAssets :: forall a. (Typeable a) => Schedule IO () ()+loadAssets = proc () -> do+ server <- reader $ S.single (Q.fetch @QueryReader @(AssetServer a)) -< ()+ server' <-+ task+ ( \server ->+ foldrM+ ( \(aId, v) acc -> do+ case v of+ Right r -> do+ maybeSurface <- readIORef r+ case maybeSurface of+ Just surface ->+ return+ acc+ { assetServerAssets = Map.insert aId surface (assetServerAssets acc),+ loadingAssets = Map.delete aId (loadingAssets acc)+ }+ Nothing -> return acc+ Left f -> do+ v' <- f+ return $ acc {loadingAssets = Map.insert aId (Right v') (loadingAssets server)}+ )+ server+ (Map.toList $ loadingAssets server)+ )+ -<+ server+ system $ S.mapSingle Q.set -< server'+ returnA -< ()++setup :: forall a. (Typeable a) => System () ()+setup = S.queue . const . A.spawn_ . bundle $ empty @a
+ src/Aztecs/Camera.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE Arrows #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeApplications #-}++module Aztecs.Camera+ ( Camera (..),+ CameraTarget (..),+ addCameraTargets,+ )+where++import Aztecs.ECS+import qualified Aztecs.ECS.Access as A+import Aztecs.ECS.Query.Reader (ArrowQueryReader)+import qualified Aztecs.ECS.Query.Reader as Q+import Aztecs.ECS.System (ArrowReaderSystem, ArrowSystem)+import qualified Aztecs.ECS.System as S+import Aztecs.Window (Window)+import Control.Arrow (Arrow (..))+import Control.DeepSeq+import GHC.Generics (Generic)+import Linear (V2 (..))++-- | Camera component.+data Camera = Camera+ { -- | Camera viewport size.+ cameraViewport :: !(V2 Int),+ -- | Camera scale factor.+ cameraScale :: !(V2 Float)+ }+ deriving (Show, Generic, NFData)++instance Component Camera++-- | Camera target component.+newtype CameraTarget = CameraTarget+ { -- | This camera's target window.+ cameraTargetWindow :: EntityID+ }+ deriving (Eq, Show, Generic, NFData)++instance Component CameraTarget++-- | Add `CameraTarget` components to entities with a new `Draw` component.+addCameraTargets :: (ArrowQueryReader qr, ArrowReaderSystem qr arr, ArrowSystem q arr) => arr () ()+addCameraTargets = proc () -> do+ windows <- S.all (Q.entity &&& Q.fetch @_ @Window) -< ()+ newCameras <- S.filter (Q.entity &&& Q.fetch @_ @Camera) (without @CameraTarget) -< ()+ S.queue+ ( \(newCameras, windows) -> case windows of+ (windowEId, _) : _ -> mapM_ (\(eId, _) -> A.insert eId $ CameraTarget windowEId) newCameras+ _ -> return ()+ )+ -<+ (newCameras, windows)
+ src/Aztecs/ECS.hs view
@@ -0,0 +1,94 @@+-- | Aztecs is a type-safe and friendly ECS for games and more.+--+-- An ECS is a modern approach to organizing your application state as a database,+-- providing patterns for data-oriented design and parallel processing.+--+-- The ECS architecture is composed of three main concepts:+--+-- === Entities+-- An entity is an object comprised of zero or more components.+-- In Aztecs, entities are represented by their `EntityID`, a unique identifier.+--+-- === Components+-- A `Component` holds the data for a particular aspect of an entity.+-- For example, a zombie entity might have a @Health@ and a @Transform@ component.+--+-- > newtype Position = Position Int deriving (Show)+-- > instance Component Position+-- >+-- > newtype Velocity = Velocity Int deriving (Show)+-- > instance Component Velocity+--+-- === Systems+-- A `System` is a pipeline that processes entities and their components.+-- Systems in Aztecs either run in sequence or in parallel automatically based on the components they access.+--+-- Systems can access game state in two ways:+--+-- ==== Access+-- An `Access` can be queued for full access to the `World`, after a system is complete.+-- `Access` allows for spawning, inserting, and removing components.+--+-- > setup :: System () ()+-- > setup = S.queue . const . A.spawn_ $ bundle (Position 0) <> bundle (Velocity 1)+--+-- ==== Queries+-- A `Query` can read and write matching components.+--+-- > move :: System () ()+-- > move =+-- > S.map+-- > ( proc () -> do+-- > Velocity v <- Q.fetch -< ()+-- > Position p <- Q.fetch -< ()+-- > Q.set -< Position $ p + v+-- > )+-- > >>> S.run print+--+-- Finally, systems can be run on a `World` to produce a result.+--+-- > main :: IO ()+-- > main = runSystem_ $ setup >>> S.forever move+module Aztecs.ECS+ ( Access,+ runAccessT,+ Bundle,+ bundle,+ Component (..),+ EntityID,+ Query,+ QueryFilter,+ with,+ without,+ System,+ Schedule,+ reader,+ system,+ forever,+ forever_,+ access,+ task,+ runSchedule,+ runSchedule_,+ World,+ )+where++import Aztecs.ECS.Access (Access, runAccessT)+import Aztecs.ECS.Component (Component (..))+import Aztecs.ECS.Entity (EntityID)+import Aztecs.ECS.Query (Query, QueryFilter, with, without)+import Aztecs.ECS.Schedule+ ( Schedule,+ access,+ forever,+ forever_,+ reader,+ runSchedule,+ runSchedule_,+ system,+ task,+ )+import Aztecs.ECS.System (System)+import Aztecs.ECS.World (World)+import Aztecs.ECS.World.Archetype (Bundle, bundle)
+ src/Aztecs/ECS/Access.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Aztecs.ECS.Access+ ( Access,+ AccessT (..),+ MonadAccess (..),+ runAccessT,+ )+where++import Aztecs.ECS.Access.Class (MonadAccess (..))+import Aztecs.ECS.World (World (..))+import qualified Aztecs.ECS.World as W+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.Identity (Identity)+import Control.Monad.State.Strict (MonadState (..), StateT (..))+import Prelude hiding (all, lookup, map)++type Access = AccessT Identity++-- | Access into the `World`.+newtype AccessT m a = AccessT {unAccessT :: StateT World m a}+ deriving (Functor, Applicative, Monad, MonadIO)++-- | Run an `Access` on a `World`, returning the output and updated `World`.+runAccessT :: (Functor m) => AccessT m a -> World -> m (a, World)+runAccessT a = runStateT $ unAccessT a++instance (Monad m) => MonadAccess (AccessT m) where+ spawn b = AccessT $ do+ !w <- get+ let !(e, w') = W.spawn b w+ put w'+ return e+ insert e c = AccessT $ do+ !w <- get+ let !w' = W.insert e c w+ put w'+ lookup e = AccessT $ do+ !w <- get+ return $ W.lookup e w+ remove e = AccessT $ do+ !w <- get+ let !(a, w') = W.remove e w+ put w'+ return a+ despawn e = AccessT $ do+ !w <- get+ let !(_, w') = W.despawn e w+ put w'
+ src/Aztecs/ECS/Access/Class.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE FlexibleContexts #-}++module Aztecs.ECS.Access.Class (MonadAccess (..)) where++import Aztecs.ECS.Component (Component (..))+import Aztecs.ECS.Entity (EntityID (..))+import Aztecs.ECS.World.Archetype (Bundle (..))+import Data.Data (Typeable)+import Prelude hiding (all, lookup, map)++-- | Monadic access to a `World`.+class (Monad m) => MonadAccess m where+ -- | Spawn an entity with a component.+ spawn :: Bundle -> m EntityID++ -- | Spawn an entity with a component.+ spawn_ :: Bundle -> m ()+ spawn_ c = do+ _ <- spawn c+ return ()++ -- | Insert a component into an entity.+ insert :: (Component a, Typeable (StorageT a)) => EntityID -> a -> m ()++ -- | Lookup a component on an entity.+ lookup :: (Component a) => EntityID -> m (Maybe a)++ -- | Remove a component from an entity.+ remove :: (Component a, Typeable (StorageT a)) => EntityID -> m (Maybe a)++ -- | Despawn an entity.+ despawn :: EntityID -> m ()
+ src/Aztecs/ECS/Component.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.ECS.Component (Component (..), ComponentID (..)) where++import Aztecs.ECS.World.Storage (Storage)+import Control.DeepSeq (NFData)+import Data.IntMap.Strict (IntMap)+import Data.Kind (Type)+import Data.Typeable (Typeable)+import GHC.Generics (Generic)++-- | Component ID.+newtype ComponentID = ComponentID {unComponentId :: Int}+ deriving (Eq, Ord, Show, Generic, NFData)++-- | Component that can be stored in the `World`.+class (Typeable a, Storage (StorageT a) a) => Component a where+ -- | `Storage` of this component.+ type StorageT a :: Type -> Type++ type StorageT a = IntMap
+ src/Aztecs/ECS/Entity.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Aztecs.ECS.Entity (EntityID (..)) where++import Control.DeepSeq (NFData)+import GHC.Generics (Generic)++-- | Entity ID.+newtype EntityID = EntityID {unEntityId :: Int}+ deriving (Eq, Ord, Show, Generic, NFData)
+ src/Aztecs/ECS/Query.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.ECS.Query+ ( -- * Queries+ Query (..),+ ArrowQueryReader (..),+ ArrowQuery (..),+ ArrowDynamicQueryReader (..),+ ArrowDynamicQuery (..),++ -- ** Running+ all,++ -- * Filters+ QueryFilter (..),+ with,+ without,++ -- * Reads and writes+ ReadsWrites (..),+ disjoint,+ )+where++import Aztecs.ECS.Component+import Aztecs.ECS.Query.Class (ArrowQuery (..))+import Aztecs.ECS.Query.Dynamic (DynamicQuery (..))+import Aztecs.ECS.Query.Dynamic.Class (ArrowDynamicQuery (..))+import Aztecs.ECS.Query.Dynamic.Reader.Class (ArrowDynamicQueryReader (..))+import Aztecs.ECS.Query.Reader (QueryFilter (..), with, without)+import Aztecs.ECS.Query.Reader.Class (ArrowQueryReader (..))+import Aztecs.ECS.World (World (..))+import qualified Aztecs.ECS.World.Archetype as A+import Aztecs.ECS.World.Archetypes (Node (..))+import qualified Aztecs.ECS.World.Archetypes as AS+import Aztecs.ECS.World.Components (Components)+import qualified Aztecs.ECS.World.Components as CS+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))+import Data.Set (Set)+import qualified Data.Set as Set+import Prelude hiding (all, id, reads, (.))++-- | Query for matching entities.+--+-- === Do notation:+-- > move :: (Monad m) => Query m () Position+-- > move = proc () -> do+-- > Velocity v <- Q.fetch -< ()+-- > Position p <- Q.fetch -< ()+-- > Q.set -< Position $ p + v+--+-- === Arrow combinators:+-- > move :: (Monad m) => Query m () Position+-- > move = Q.fetch &&& Q.fetch >>> arr (\(Position p, Velocity v) -> Position $ p + v) >>> Q.set+--+-- === Applicative combinators:+-- > move :: (Monad m) => Query m () Position+-- > move = (,) <$> Q.fetch <*> Q.fetch >>> arr (\(Position p, Velocity v) -> Position $ p + v) >>> Q.set+newtype Query i o+ = Query {runQuery :: Components -> (ReadsWrites, Components, DynamicQuery i o)}++instance Functor (Query i) where+ fmap f (Query q) = Query $ \cs -> let (cIds, cs', qS) = q cs in (cIds, cs', fmap f qS)++instance Applicative (Query i) where+ pure a = Query (mempty,,pure a)+ (Query f) <*> (Query g) = Query $ \cs ->+ let (cIdsG, cs', aQS) = g cs+ (cIdsF, cs'', bQS) = f cs'+ in (cIdsG <> cIdsF, cs'', bQS <*> aQS)++instance Category Query where+ id = Query (mempty,,id)+ (Query f) . (Query g) = Query $ \cs ->+ let (cIdsG, cs', aQS) = g cs+ (cIdsF, cs'', bQS) = f cs'+ in (cIdsG <> cIdsF, cs'', bQS . aQS)++instance Arrow Query where+ arr f = Query (mempty,,arr f)+ first (Query f) = Query $ \comps -> let (cIds, comps', qS) = f comps in (cIds, comps', first qS)++instance ArrowQueryReader Query where+ entity = Query (mempty,,entityDyn)+ fetch :: forall a. (Component a) => Query () a+ fetch = Query $ \cs ->+ let (cId, cs') = CS.insert @a cs+ in (ReadsWrites (Set.singleton cId) Set.empty, cs', fetchDyn cId)+ fetchMaybe :: forall a. (Component a) => Query () (Maybe a)+ fetchMaybe = Query $ \cs ->+ let (cId, cs') = CS.insert @a cs+ in (ReadsWrites (Set.singleton cId) Set.empty, cs', fetchMaybeDyn cId)++instance ArrowDynamicQueryReader Query where+ entityDyn = Query (mempty,,entityDyn)+ fetchDyn cId = Query (ReadsWrites (Set.singleton cId) Set.empty,,fetchDyn cId)+ fetchMaybeDyn cId = Query (ReadsWrites (Set.singleton cId) Set.empty,,fetchMaybeDyn cId)++instance ArrowDynamicQuery Query where+ setDyn cId = Query (ReadsWrites Set.empty (Set.singleton cId),,setDyn cId)++instance ArrowQuery Query where+ set :: forall a. (Component a) => Query a a+ set = Query $ \cs ->+ let (cId, cs') = CS.insert @a cs+ in (ReadsWrites Set.empty (Set.singleton cId), cs', setDyn cId)++data ReadsWrites = ReadsWrites+ { reads :: !(Set ComponentID),+ writes :: !(Set ComponentID)+ }+ deriving (Show)++instance Semigroup ReadsWrites where+ ReadsWrites r1 w1 <> ReadsWrites r2 w2 = ReadsWrites (r1 <> r2) (w1 <> w2)++instance Monoid ReadsWrites where+ mempty = ReadsWrites mempty mempty++disjoint :: ReadsWrites -> ReadsWrites -> Bool+disjoint a b =+ Set.disjoint (reads a) (writes b)+ || Set.disjoint (reads b) (writes a)+ || Set.disjoint (writes b) (writes a)++all :: Query () a -> World -> ([a], World)+all q w =+ let (rws, cs', dynQ) = runQuery q (components w)+ as =+ fmap+ (\n -> fst $ dynQueryAll dynQ (repeat ()) (A.entities $ nodeArchetype n) (nodeArchetype n))+ (AS.lookup (reads rws <> writes rws) (archetypes w))+ in (concat as, w {components = cs'})
+ src/Aztecs/ECS/Query/Class.hs view
@@ -0,0 +1,8 @@+module Aztecs.ECS.Query.Class (ArrowQuery (..)) where++import Aztecs.ECS.Component+import Aztecs.ECS.Query.Reader.Class (ArrowQueryReader)++class (ArrowQueryReader arr) => ArrowQuery arr where+ -- | Set a `Component` by its type.+ set :: (Component a) => arr a a
+ src/Aztecs/ECS/Query/Dynamic.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.ECS.Query.Dynamic+ ( -- * Dynamic queries+ DynamicQuery (..),+ ArrowDynamicQueryReader (..),+ ArrowDynamicQuery (..),++ -- * Dynamic query filters+ DynamicQueryFilter (..),+ )+where++import Aztecs.ECS.Entity (EntityID)+import Aztecs.ECS.Query.Dynamic.Class (ArrowDynamicQuery (..))+import Aztecs.ECS.Query.Dynamic.Reader (DynamicQueryFilter (..))+import Aztecs.ECS.Query.Dynamic.Reader.Class (ArrowDynamicQueryReader (..))+import Aztecs.ECS.World.Archetype (Archetype)+import qualified Aztecs.ECS.World.Archetype as A+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))+import Prelude hiding (all, any, id, lookup, map, mapM, reads, (.))++-- | Dynamic query for components by ID.+newtype DynamicQuery i o+ = DynamicQuery {dynQueryAll :: [i] -> [EntityID] -> Archetype -> ([o], Archetype)}++instance Functor (DynamicQuery i) where+ fmap f q =+ DynamicQuery $ \i es arch ->+ let (a, arch') = dynQueryAll q i es arch+ in (fmap f a, arch')++instance Applicative (DynamicQuery i) where+ pure a = DynamicQuery $ \_ es arch -> (replicate (length es) a, arch)++ f <*> g =+ DynamicQuery+ { dynQueryAll = \i es arch ->+ let (as, arch') = dynQueryAll g i es arch+ (fs, arch'') = dynQueryAll f i es arch'+ in (zipWith ($) fs as, arch'')+ }++instance Category DynamicQuery where+ id = DynamicQuery $ \as _ arch -> (as, arch)++ f . g =+ DynamicQuery+ { dynQueryAll = \i es arch ->+ let (as, arch') = dynQueryAll g i es arch+ in dynQueryAll f as es arch'+ }++instance Arrow DynamicQuery where+ arr f = DynamicQuery $ \bs _ arch -> (fmap f bs, arch)+ first f =+ DynamicQuery+ { dynQueryAll = \bds es arch ->+ let (bs, ds) = unzip bds+ (cs, arch') = dynQueryAll f bs es arch+ in (zip cs ds, arch')+ }++instance ArrowDynamicQueryReader DynamicQuery where+ entityDyn = DynamicQuery $ \_ es arch -> (es, arch)++ fetchDyn cId =+ DynamicQuery $ \_ _ arch -> let !as = A.all cId arch in (fmap snd as, arch)++ fetchMaybeDyn cId =+ DynamicQuery $ \_ _ arch -> let as = A.allMaybe cId arch in (fmap snd as, arch)++instance ArrowDynamicQuery DynamicQuery where+ setDyn cId =+ DynamicQuery $ \is _ arch -> let !arch' = A.withAscList cId is arch in (is, arch')
+ src/Aztecs/ECS/Query/Dynamic/Class.hs view
@@ -0,0 +1,7 @@+module Aztecs.ECS.Query.Dynamic.Class (ArrowDynamicQuery (..)) where++import Aztecs.ECS.Component+import Aztecs.ECS.Query.Dynamic.Reader.Class (ArrowDynamicQueryReader)++class (ArrowDynamicQueryReader arr) => ArrowDynamicQuery arr where+ setDyn :: (Component a) => ComponentID -> arr a a
+ src/Aztecs/ECS/Query/Dynamic/Reader.hs view
@@ -0,0 +1,69 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.ECS.Query.Dynamic.Reader+ ( -- * Dynamic queries+ DynamicQueryReader (..),+ ArrowDynamicQueryReader (..),++ -- * Dynamic query filters+ DynamicQueryFilter (..),+ )+where++import Aztecs.ECS.Component+import Aztecs.ECS.Entity (EntityID)+import Aztecs.ECS.Query.Dynamic.Reader.Class (ArrowDynamicQueryReader (..))+import Aztecs.ECS.World.Archetype (Archetype)+import qualified Aztecs.ECS.World.Archetype as A+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))+import Data.Set (Set)+import Prelude hiding (all, any, id, lookup, map, mapM, reads, (.))++-- | Dynamic query for components by ID.+newtype DynamicQueryReader i o+ = DynamicQueryReader {dynQueryReaderAll :: [i] -> [EntityID] -> Archetype -> [o]}++instance Functor (DynamicQueryReader i) where+ fmap f q = DynamicQueryReader $ \i es arch -> f <$> dynQueryReaderAll q i es arch++instance Applicative (DynamicQueryReader i) where+ pure a = DynamicQueryReader $ \_ es _ -> replicate (length es) a++ f <*> g =+ DynamicQueryReader $ \i es arch ->+ let as = dynQueryReaderAll g i es arch+ fs = dynQueryReaderAll f i es arch+ in zipWith ($) fs as++instance Category DynamicQueryReader where+ id = DynamicQueryReader $ \as _ _ -> as+ f . g = DynamicQueryReader $ \i es arch ->+ let as = dynQueryReaderAll g i es arch in dynQueryReaderAll f as es arch++instance Arrow DynamicQueryReader where+ arr f = DynamicQueryReader $ \bs _ _ -> fmap f bs+ first f = DynamicQueryReader $ \bds es arch ->+ let (bs, ds) = unzip bds+ cs = dynQueryReaderAll f bs es arch+ in zip cs ds++instance ArrowDynamicQueryReader DynamicQueryReader where+ entityDyn = DynamicQueryReader $ \_ es _ -> es+ fetchDyn cId =+ DynamicQueryReader $ \_ _ arch -> let !as = A.all cId arch in fmap snd as+ fetchMaybeDyn cId =+ DynamicQueryReader $ \_ _ arch -> let as = A.allMaybe cId arch in fmap snd as++data DynamicQueryFilter = DynamicQueryFilter+ { filterWith :: !(Set ComponentID),+ filterWithout :: !(Set ComponentID)+ }++instance Semigroup DynamicQueryFilter where+ DynamicQueryFilter withA withoutA <> DynamicQueryFilter withB withoutB =+ DynamicQueryFilter (withA <> withB) (withoutA <> withoutB)++instance Monoid DynamicQueryFilter where+ mempty = DynamicQueryFilter mempty mempty
+ src/Aztecs/ECS/Query/Dynamic/Reader/Class.hs view
@@ -0,0 +1,16 @@+module Aztecs.ECS.Query.Dynamic.Reader.Class (ArrowDynamicQueryReader (..)) where++import Aztecs.ECS.Component+import Aztecs.ECS.Entity (EntityID)+import Control.Arrow (Arrow (..), (>>>))++class (Arrow arr) => ArrowDynamicQueryReader arr where+ -- | Fetch the `EntityID` belonging to this entity.+ entityDyn :: arr () EntityID++ -- | Fetch a `Component` by its `ComponentID`.+ fetchDyn :: (Component a) => ComponentID -> arr () a++ -- | Try to fetch a `Component` by its `ComponentID`.+ fetchMaybeDyn :: (Component a) => ComponentID -> arr () (Maybe a)+ fetchMaybeDyn cId = fetchDyn cId >>> arr Just
+ src/Aztecs/ECS/Query/Reader.hs view
@@ -0,0 +1,114 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.ECS.Query.Reader+ ( -- * Queries+ QueryReader (..),+ ArrowQueryReader (..),+ ArrowDynamicQueryReader (..),++ -- * Filters+ QueryFilter (..),+ with,+ without,+ DynamicQueryFilter (..),+ )+where++import Aztecs.ECS.Component+import Aztecs.ECS.Query.Dynamic (DynamicQueryFilter (..))+import Aztecs.ECS.Query.Dynamic.Reader (DynamicQueryReader (..))+import Aztecs.ECS.Query.Dynamic.Reader.Class (ArrowDynamicQueryReader (..))+import Aztecs.ECS.Query.Reader.Class (ArrowQueryReader (..))+import Aztecs.ECS.World.Components (Components)+import qualified Aztecs.ECS.World.Components as CS+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))+import Data.Set (Set)+import qualified Data.Set as Set+import Prelude hiding (id, (.))++-- | Query for matching entities.+--+-- === Do notation:+-- > move :: (Monad m) => Query m () Position+-- > move = proc () -> do+-- > Velocity v <- Q.fetch -< ()+-- > Position p <- Q.fetch -< ()+-- > Q.set -< Position $ p + v+--+-- === Arrow combinators:+-- > move :: (Monad m) => Query m () Position+-- > move = Q.fetch &&& Q.fetch >>> arr (\(Position p, Velocity v) -> Position $ p + v) >>> Q.set+--+-- === Applicative combinators:+-- > move :: (Monad m) => Query m () Position+-- > move = (,) <$> Q.fetch <*> Q.fetch >>> arr (\(Position p, Velocity v) -> Position $ p + v) >>> Q.set+newtype QueryReader i o+ = Query {runQueryReader :: Components -> (Set ComponentID, Components, DynamicQueryReader i o)}++instance Functor (QueryReader i) where+ fmap f (Query q) = Query $ \cs -> let (cIds, cs', qS) = q cs in (cIds, cs', fmap f qS)++instance Applicative (QueryReader i) where+ pure a = Query $ \cs -> (mempty, cs, pure a)+ (Query f) <*> (Query g) = Query $ \cs ->+ let (cIdsG, cs', aQS) = g cs+ (cIdsF, cs'', bQS) = f cs'+ in (cIdsG <> cIdsF, cs'', bQS <*> aQS)++instance Category QueryReader where+ id = Query $ \cs -> (mempty, cs, id)+ (Query f) . (Query g) = Query $ \cs ->+ let (cIdsG, cs', aQS) = g cs+ (cIdsF, cs'', bQS) = f cs'+ in (cIdsG <> cIdsF, cs'', bQS . aQS)++instance Arrow QueryReader where+ arr f = Query $ \cs -> (mempty, cs, arr f)+ first (Query f) = Query $ \comps -> let (cIds, comps', qS) = f comps in (cIds, comps', first qS)++instance ArrowQueryReader QueryReader where+ entity = Query $ \cs -> (mempty, cs, entityDyn)+ fetch :: forall a. (Component a) => QueryReader () a+ fetch = Query $ \cs ->+ let (cId, cs') = CS.insert @a cs+ in (Set.singleton cId, cs', fetchDyn cId)+ fetchMaybe :: forall a. (Component a) => QueryReader () (Maybe a)+ fetchMaybe = Query $ \cs ->+ let (cId, cs') = CS.insert @a cs+ in (Set.singleton cId, cs', fetchMaybeDyn cId)++instance ArrowDynamicQueryReader QueryReader where+ entityDyn = Query $ \cs -> (mempty, cs, entityDyn)+ fetchDyn cId = Query $ \cs -> (Set.singleton cId, cs, fetchDyn cId)+ fetchMaybeDyn cId = Query $ \cs -> (Set.singleton cId, cs, fetchMaybeDyn cId)++-- | Filter for a `Query`.+newtype QueryFilter = QueryFilter {runQueryFilter :: Components -> (DynamicQueryFilter, Components)}++instance Semigroup QueryFilter where+ a <> b =+ QueryFilter+ ( \cs ->+ let (withA', cs') = runQueryFilter a cs+ (withB', cs'') = runQueryFilter b cs'+ in (withA' <> withB', cs'')+ )++instance Monoid QueryFilter where+ mempty = QueryFilter (mempty,)++-- | Filter for entities containing this component.+with :: forall a. (Component a) => QueryFilter+with = QueryFilter $ \cs ->+ let (cId, cs') = CS.insert @a cs in (mempty {filterWith = Set.singleton cId}, cs')++-- | Filter out entities containing this component.+without :: forall a. (Component a) => QueryFilter+without = QueryFilter $ \cs ->+ let (cId, cs') = CS.insert @a cs in (mempty {filterWithout = Set.singleton cId}, cs')
+ src/Aztecs/ECS/Query/Reader/Class.hs view
@@ -0,0 +1,16 @@+module Aztecs.ECS.Query.Reader.Class (ArrowQueryReader (..)) where++import Aztecs.ECS.Component+import Aztecs.ECS.Entity (EntityID)+import Control.Arrow (Arrow (..), (>>>))++class (Arrow arr) => ArrowQueryReader arr where+ -- | Fetch the currently matched `EntityID`.+ entity :: arr () EntityID++ -- | Fetch a `Component` by its type.+ fetch :: (Component a) => arr () a++ -- | Fetch a `Component` by its type, returning `Nothing` if it doesn't exist.+ fetchMaybe :: (Component a) => arr () (Maybe a)+ fetchMaybe = fetch >>> arr Just
+ src/Aztecs/ECS/Schedule.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}++module Aztecs.ECS.Schedule+ ( -- * Schedules+ Schedule (..),+ reader,+ system,+ forever,+ forever_,+ access,+ task,+ runSchedule,+ runSchedule_,+ )+where++import Aztecs.ECS.Access (AccessT (..), runAccessT)+import Aztecs.ECS.System (System (..))+import Aztecs.ECS.System.Dynamic (DynamicSystem (..))+import Aztecs.ECS.System.Dynamic.Reader (DynamicReaderSystem (..))+import Aztecs.ECS.System.Reader (ReaderSystem (..))+import qualified Aztecs.ECS.View as V+import Aztecs.ECS.World (World (..))+import qualified Aztecs.ECS.World as W+import Aztecs.ECS.World.Components (Components)+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))+import Control.DeepSeq+import Control.Exception (evaluate)+import Control.Monad ((>=>))+import Control.Monad.Identity (Identity (runIdentity))+import Control.Monad.State (MonadState (..))+import Control.Monad.Trans (MonadTrans (..))+import Data.Functor (void)++newtype Schedule m i o = Schedule {runSchedule' :: Components -> (i -> AccessT m o, Components)}+ deriving (Functor)++instance (Monad m) => Category (Schedule m) where+ id = Schedule $ \cs -> (return, cs)+ Schedule f . Schedule g = Schedule $ \cs ->+ let (g', cs') = g cs+ (f', cs'') = f cs'+ in (g' >=> f', cs'')++instance Arrow (Schedule IO) where+ arr f = Schedule $ \cs -> (return Prelude.. f, cs)+ first (Schedule f) = Schedule $ \cs ->+ let (g, cs') = f cs in (\(b, d) -> (,) <$> g b <*> return d, cs')++runSchedule :: (Monad m) => Schedule m i o -> World -> i -> m (o, World)+runSchedule s w i = do+ let (f, cs) = runSchedule' s (components w)+ (o, w') <- runAccessT (f i) w {components = cs}+ return (o, w')++runSchedule_ :: (Monad m) => Schedule m () () -> m ()+runSchedule_ s = void (runSchedule s W.empty ())++reader :: (Monad m) => ReaderSystem i o -> Schedule m i o+reader t = Schedule $ \cs ->+ let (dynT, _, cs') = runReaderSystem t cs+ go i = AccessT $ do+ w <- get+ return $ runReaderSystemDyn dynT w i+ in (go, cs')++system :: (Monad m) => System i o -> Schedule m i o+system t = Schedule $ \cs ->+ let (dynT, _, cs') = runSystem t cs+ go i = AccessT $ do+ w <- get+ let (o, v, a) = runSystemDyn dynT w i+ ((), w') = runIdentity $ runAccessT a $ V.unview v w+ put w'+ return o+ in (go, cs')++access :: (Monad m) => (i -> AccessT m o) -> Schedule m i o+access f = Schedule $ \cs -> (f, cs)++task :: (Monad m) => (i -> m o) -> Schedule m i o+task f = Schedule $ \cs -> (AccessT Prelude.. lift Prelude.. f, cs)++forever :: Schedule IO i o -> (o -> IO ()) -> Schedule IO i ()+forever s f = Schedule $ \cs ->+ let (g, cs') = runSchedule' s cs+ go i = AccessT $ do+ w <- get+ let loop wAcc = do+ (o, wAcc') <- lift $ runAccessT (g i) wAcc+ lift $ evaluate $ rnf wAcc'+ lift $ f o+ loop wAcc'+ loop w+ in (go, cs')++forever_ :: Schedule IO i o -> Schedule IO i ()+forever_ s = forever s (const $ pure ())
+ src/Aztecs/ECS/System.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Aztecs.ECS.System+ ( -- * Systems+ System (..),+ ArrowReaderSystem (..),+ ArrowSystem (..),+ )+where++import Aztecs.ECS.Query (Query (..), QueryFilter (..), ReadsWrites (..))+import qualified Aztecs.ECS.Query as Q+import Aztecs.ECS.Query.Reader (QueryReader (..), filterWith, filterWithout)+import Aztecs.ECS.System.Class (ArrowSystem (..), filterMap, map, mapSingle, map_, queue)+import Aztecs.ECS.System.Dynamic (DynamicSystem (..), raceDyn)+import Aztecs.ECS.System.Dynamic.Class (ArrowDynamicSystem (..))+import Aztecs.ECS.System.Dynamic.Reader.Class (ArrowDynamicReaderSystem (..))+import Aztecs.ECS.System.Reader.Class (ArrowReaderSystem (..), all, filter, single)+import qualified Aztecs.ECS.World.Archetype as A+import Aztecs.ECS.World.Archetypes (Node (..))+import Aztecs.ECS.World.Components (Components)+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))+import qualified Data.Foldable as F+import Prelude hiding (all, filter, map, (.))+import qualified Prelude hiding (filter, map)++-- | System to process entities.+newtype System i o = System+ { -- | Run a system, producing a `DynamicSystem` that can be repeatedly run.+ runSystem :: Components -> (DynamicSystem i o, ReadsWrites, Components)+ }+ deriving (Functor)++instance Category System where+ id = System $ \cs -> (DynamicSystem $ \_ i -> (i, mempty, pure ()), mempty, cs)+ System f . System g = System $ \cs ->+ let (f', rwsF, cs') = f cs+ (g', rwsG, cs'') = g cs'+ in (f' . g', rwsF <> rwsG, cs'')++instance Arrow System where+ arr f = System $ \cs -> (DynamicSystem $ \_ i -> (f i, mempty, pure ()), mempty, cs)+ first (System f) = System $ \cs ->+ let (f', rwsF, cs') = f cs in (first f', rwsF, cs')+ f &&& g = System $ \cs ->+ let (dynF, rwsA, cs') = runSystem f cs+ (dynG, rwsB, cs'') = runSystem g cs'+ in ( if Q.disjoint rwsA rwsB then dynF &&& dynG else raceDyn dynF dynG,+ rwsA <> rwsB,+ cs''+ )++instance ArrowReaderSystem QueryReader System where+ all q = System $ \cs ->+ let !(rs, cs', dynQ) = runQueryReader q cs in (allDyn rs dynQ, ReadsWrites rs mempty, cs')+ filter q qf = System $ \cs ->+ let !(rs, cs', dynQ) = runQueryReader q cs+ !(dynQf, cs'') = runQueryFilter qf cs'+ qf' n =+ F.all (\cId -> A.member cId $ nodeArchetype n) (filterWith dynQf)+ && F.all (\cId -> not (A.member cId $ nodeArchetype n)) (filterWithout dynQf)+ in (filterDyn rs dynQ qf', ReadsWrites rs mempty, cs'')++instance ArrowSystem Query System where+ map q = System $ \cs ->+ let !(rws, cs', dynQ) = runQuery q cs+ in (mapDyn (Q.reads rws <> Q.writes rws) dynQ, rws, cs')+ filterMap q qf = System $ \cs ->+ let !(rws, cs', dynQ) = runQuery q cs+ !(dynQf, cs'') = runQueryFilter qf cs'+ f' n =+ F.all (\cId -> A.member cId $ nodeArchetype n) (filterWith dynQf)+ && F.all (\cId -> not (A.member cId $ nodeArchetype n)) (filterWithout dynQf)+ in (filterMapDyn (Q.reads rws <> Q.writes rws) dynQ f', rws, cs'')+ mapSingle q = System $ \cs ->+ let !(rws, cs', dynQ) = runQuery q cs+ in (mapSingleDyn (Q.reads rws <> Q.writes rws) dynQ, rws, cs')+ mapSingleMaybe q = System $ \cs ->+ let !(rws, cs', dynQ) = runQuery q cs+ in (mapSingleMaybeDyn (Q.reads rws <> Q.writes rws) dynQ, rws, cs')+ queue f = System $ \cs -> (queueDyn f, mempty, cs)
+ src/Aztecs/ECS/System/Class.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE FunctionalDependencies #-}++module Aztecs.ECS.System.Class (ArrowSystem (..)) where++import Aztecs.ECS.Access (Access)+import Aztecs.ECS.Query.Reader (QueryFilter (..))+import Control.Arrow (Arrow (..), (>>>))+import Prelude hiding (map)++class (Arrow arr) => ArrowSystem q arr | arr -> q where+ -- | Query and update all matching entities.+ map :: q i a -> arr i [a]++ -- | Query and update all matching entities, ignoring the results.+ map_ :: q i o -> arr i ()+ map_ q = map q >>> arr (const ())++ -- | Map all matching entities with a `QueryFilter`, storing the updated entities.+ filterMap :: q i a -> QueryFilter -> arr i [a]++ -- | Map a single matching entity, storing the updated components.+ -- If there are zero or multiple matching entities, an error will be thrown.+ mapSingle :: q i a -> arr i a++ mapSingleMaybe :: q i a -> arr i (Maybe a)++ -- | Queue an `Access` to happen after this system schedule.+ queue :: (i -> Access ()) -> arr i ()
+ src/Aztecs/ECS/System/Dynamic.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Aztecs.ECS.System.Dynamic (DynamicSystem (..), raceDyn) where++import Aztecs.ECS.Access (Access)+import Aztecs.ECS.System.Dynamic.Class (ArrowDynamicSystem (..))+import Aztecs.ECS.System.Dynamic.Reader.Class (ArrowDynamicReaderSystem (..))+import Aztecs.ECS.View (View, filterView, readAllDyn, view)+import Aztecs.ECS.World (World (..))+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))+import Control.Parallel (par)++newtype DynamicSystem i o = DynamicSystem+ { -- | Run a dynamic system,+ -- producing some output, an updated `View` into the `World`, and any queued `Access`.+ runSystemDyn :: World -> (i -> (o, View, Access ()))+ }+ deriving (Functor)++instance Category DynamicSystem where+ id = DynamicSystem $ \_ i -> (i, mempty, pure ())+ DynamicSystem f . DynamicSystem g = DynamicSystem $ \w i ->+ let (b, gView, gAccess) = g w i+ (a, fView, fAccess) = f w b+ in (a, gView <> fView, gAccess >> fAccess)++instance Arrow DynamicSystem where+ arr f = DynamicSystem $ \_ i -> (f i, mempty, pure ())+ first (DynamicSystem f) = DynamicSystem $ \w (i, x) -> let (a, v, access) = f w i in ((a, x), v, access)++instance ArrowDynamicReaderSystem DynamicSystem where+ allDyn cIds q = DynamicSystem $ \w i ->+ let v = view cIds $ archetypes w in (readAllDyn i q v, v, pure ())+ filterDyn cIds q f = DynamicSystem $ \w i ->+ let v = filterView cIds f $ archetypes w in (readAllDyn i q v, v, pure ())++instance ArrowDynamicSystem DynamicSystem where+ runArrowSystemDyn = DynamicSystem++raceDyn :: DynamicSystem i a -> DynamicSystem i b -> DynamicSystem i (a, b)+raceDyn (DynamicSystem f) (DynamicSystem g) = DynamicSystem $ \w i ->+ let fa = f w i+ gb = g w i+ gbPar = fa `par` gb+ (a, v, fAccess) = fa+ (b, v', gAccess) = gbPar+ in ((a, b), v <> v', fAccess >> gAccess)
+ src/Aztecs/ECS/System/Dynamic/Class.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE BangPatterns #-}++module Aztecs.ECS.System.Dynamic.Class+ ( ArrowDynamicSystem (..),+ DynamicSystem,+ mapDyn',+ mapSingleDyn',+ mapSingleMaybeDyn',+ filterMapDyn',+ queueDyn',+ )+where++import Aztecs.ECS.Access (Access)+import Aztecs.ECS.Component (ComponentID)+import Aztecs.ECS.Query.Dynamic (DynamicQuery)+import Aztecs.ECS.System.Dynamic.Reader.Class (ArrowDynamicReaderSystem (..))+import Aztecs.ECS.View (View)+import qualified Aztecs.ECS.View as V+import Aztecs.ECS.World (World (..))+import Aztecs.ECS.World.Archetypes (Node (..))+import Data.Maybe (fromMaybe)+import Data.Set (Set)++type DynamicSystem i o = World -> i -> (o, View, Access ())++class (ArrowDynamicReaderSystem arr) => ArrowDynamicSystem arr where+ runArrowSystemDyn :: DynamicSystem i o -> arr i o++ -- | Map all matching entities, storing the updated entities.+ mapDyn :: Set ComponentID -> DynamicQuery i o -> arr i [o]+ mapDyn cIds q = runArrowSystemDyn $ mapDyn' cIds q++ mapSingleDyn :: Set ComponentID -> DynamicQuery i o -> arr i o+ mapSingleDyn cIds q = runArrowSystemDyn $ mapSingleDyn' cIds q++ mapSingleMaybeDyn :: Set ComponentID -> DynamicQuery i o -> arr i (Maybe o)+ mapSingleMaybeDyn cIds q = runArrowSystemDyn $ mapSingleMaybeDyn' cIds q++ filterMapDyn ::+ Set ComponentID ->+ DynamicQuery i o ->+ (Node -> Bool) ->+ arr i [o]+ filterMapDyn cIds q f = runArrowSystemDyn $ filterMapDyn' cIds q f++ queueDyn :: (i -> Access ()) -> arr i ()+ queueDyn f = runArrowSystemDyn $ \_ i -> ((), mempty, f i)++-- | Map all matching entities, storing the updated entities.+mapDyn' :: Set ComponentID -> DynamicQuery i o -> DynamicSystem i [o]+mapDyn' cIds q w =+ let !v = V.view cIds $ archetypes w+ in \i -> let (o, v') = V.allDyn i q v in (o, v', pure ())++mapSingleDyn' :: Set ComponentID -> DynamicQuery i o -> DynamicSystem i o+mapSingleDyn' cIds q w i =+ let !(maybeO, v, access) = mapSingleMaybeDyn' cIds q w i+ !o = fromMaybe (error "Expected a single matching entity.") maybeO+ in (o, v, access)++-- | Map all matching entities, storing the updated entities.+mapSingleMaybeDyn' :: Set ComponentID -> DynamicQuery i o -> DynamicSystem i (Maybe o)+mapSingleMaybeDyn' cIds q w i =+ let !res = V.viewSingle cIds $ archetypes w+ in case res of+ Just v -> let (o, v') = V.singleDyn i q v in (o, v', pure ())+ Nothing -> (Nothing, mempty, pure ())++filterMapDyn' ::+ Set ComponentID ->+ DynamicQuery i o ->+ (Node -> Bool) ->+ DynamicSystem i [o]+filterMapDyn' cIds q f w =+ let !v = V.filterView cIds f $ archetypes w+ in \i -> let (o, v') = V.allDyn i q v in (o, v', pure ())++queueDyn' :: (i -> Access ()) -> DynamicSystem i ()+queueDyn' f _ i = ((), mempty, f i)
+ src/Aztecs/ECS/System/Dynamic/Reader.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveFunctor #-}++module Aztecs.ECS.System.Dynamic.Reader+ ( -- * Dynamic Systems+ DynamicReaderSystem (..),+ ArrowDynamicReaderSystem (..),+ raceDyn,+ )+where++import Aztecs.ECS.Component (ComponentID)+import Aztecs.ECS.Query.Dynamic.Reader (DynamicQueryReader)+import Aztecs.ECS.System.Dynamic.Reader.Class (ArrowDynamicReaderSystem (..))+import qualified Aztecs.ECS.View as V+import Aztecs.ECS.World (World (..))+import Aztecs.ECS.World.Archetypes (Node)+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))+import Control.Parallel (par)+import Data.Set (Set)++newtype DynamicReaderSystem i o = DynamicReaderSystem+ { -- | Run a dynamic system producing some output+ runReaderSystemDyn :: World -> i -> o+ }+ deriving (Functor)++instance Category DynamicReaderSystem where+ id = DynamicReaderSystem $ \_ i -> i+ DynamicReaderSystem f . DynamicReaderSystem g = DynamicReaderSystem $ \w i -> let b = g w i in f w b++instance Arrow DynamicReaderSystem where+ arr f = DynamicReaderSystem $ \_ i -> f i+ first (DynamicReaderSystem f) = DynamicReaderSystem $ \w (i, x) -> let a = f w i in (a, x)++instance ArrowDynamicReaderSystem DynamicReaderSystem where+ allDyn cIds q = DynamicReaderSystem $ allDyn' cIds q+ filterDyn cIds q f = DynamicReaderSystem $ filterDyn' cIds q f++raceDyn :: DynamicReaderSystem i a -> DynamicReaderSystem i b -> DynamicReaderSystem i (a, b)+raceDyn (DynamicReaderSystem f) (DynamicReaderSystem g) = DynamicReaderSystem $ \w i ->+ let fa = f w i+ gb = g w i+ gbPar = fa `par` gb+ a = fa+ b = gbPar+ in (a, b)++allDyn' :: Set ComponentID -> DynamicQueryReader i o -> World -> i -> [o]+allDyn' cIds q w = let !v = V.view cIds $ archetypes w in \i -> V.readAllDyn i q v++filterDyn' ::+ Set ComponentID ->+ DynamicQueryReader i o ->+ (Node -> Bool) ->+ World ->+ i ->+ [o]+filterDyn' cIds q f w = let !v = V.filterView cIds f $ archetypes w in \i -> V.readAllDyn i q v
+ src/Aztecs/ECS/System/Dynamic/Reader/Class.hs view
@@ -0,0 +1,21 @@+module Aztecs.ECS.System.Dynamic.Reader.Class (ArrowDynamicReaderSystem (..)) where++import Aztecs.ECS.Component (ComponentID)+import Aztecs.ECS.Query.Dynamic.Reader (DynamicQueryReader)+import Aztecs.ECS.World.Archetypes (Node)+import Control.Arrow (Arrow (..), (>>>))+import Data.Set (Set)++class (Arrow arr) => ArrowDynamicReaderSystem arr where+ allDyn :: Set ComponentID -> DynamicQueryReader i o -> arr i [o]++ filterDyn :: Set ComponentID -> DynamicQueryReader i o -> (Node -> Bool) -> arr i [o]++ singleDyn :: Set ComponentID -> DynamicQueryReader () a -> arr () a+ singleDyn cIds q =+ allDyn cIds q+ >>> arr+ ( \as -> case as of+ [a] -> a+ _ -> error "TODO"+ )
+ src/Aztecs/ECS/System/Reader.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Aztecs.ECS.System.Reader+ ( -- * Systems+ ReaderSystem (..),+ queue,++ -- ** Queries++ -- *** Reading+ all,+ filter,+ single,++ -- *** Writing+ map,+ map_,+ filterMap,+ mapSingle,+ )+where++import Aztecs.ECS.Query.Reader+import Aztecs.ECS.System.Class (filterMap, map, mapSingle, map_, queue)+import Aztecs.ECS.System.Dynamic.Reader (DynamicReaderSystem, raceDyn)+import Aztecs.ECS.System.Dynamic.Reader.Class (ArrowDynamicReaderSystem (..))+import Aztecs.ECS.System.Reader.Class (ArrowReaderSystem (..), all, filter, single)+import qualified Aztecs.ECS.World.Archetype as A+import Aztecs.ECS.World.Archetypes (Node (..))+import Aztecs.ECS.World.Components (ComponentID, Components)+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))+import qualified Data.Foldable as F+import Data.Set (Set)+import Prelude hiding (all, filter, id, map, (.))+import qualified Prelude hiding (filter, id, map)++-- | System to process entities.+newtype ReaderSystem i o = ReaderSystem+ { -- | Run a system, producing a `DynamicSystem` that can be repeatedly run.+ runReaderSystem :: Components -> (DynamicReaderSystem i o, Set ComponentID, Components)+ }+ deriving (Functor)++instance Category ReaderSystem where+ id = ReaderSystem $ \cs -> (id, mempty, cs)+ ReaderSystem f . ReaderSystem g = ReaderSystem $ \cs ->+ let (f', rwsF, cs') = f cs+ (g', rwsG, cs'') = g cs'+ in (f' . g', rwsF <> rwsG, cs'')++instance Arrow ReaderSystem where+ arr f = ReaderSystem $ \cs -> (arr f, mempty, cs)+ first (ReaderSystem f) = ReaderSystem $ \cs ->+ let (f', rwsF, cs') = f cs+ in (first f', rwsF, cs')+ f &&& g = ReaderSystem $ \cs ->+ let (dynF, rwsA, cs') = runReaderSystem f cs+ (dynG, rwsB, cs'') = runReaderSystem g cs'+ in (raceDyn dynF dynG, rwsA <> rwsB, cs'')++instance ArrowReaderSystem QueryReader ReaderSystem where+ all q = ReaderSystem $ \cs ->+ let !(rs, cs', dynQ) = runQueryReader q cs in (allDyn rs dynQ, rs, cs')+ filter q qf = ReaderSystem $ \cs ->+ let !(rs, cs', dynQ) = runQueryReader q cs+ !(dynQf, cs'') = runQueryFilter qf cs'+ qf' n =+ F.all (\cId -> A.member cId $ nodeArchetype n) (filterWith dynQf)+ && F.all (\cId -> not (A.member cId $ nodeArchetype n)) (filterWithout dynQf)+ in (filterDyn rs dynQ qf', rs, cs'')
+ src/Aztecs/ECS/System/Reader/Class.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE FunctionalDependencies #-}++module Aztecs.ECS.System.Reader.Class (ArrowReaderSystem (..)) where++import Aztecs.ECS.Query.Reader (QueryFilter (..))+import Control.Arrow (Arrow (..), (>>>))+import Prelude hiding (all, any, filter, id, lookup, map, mapM, reads, (.))++class (Arrow arr) => ArrowReaderSystem q arr | arr -> q where+ -- | Query all matching entities.+ all :: q i a -> arr i [a]++ -- | Query all matching entities with a `QueryFilter`.+ filter :: q () a -> QueryFilter -> arr () [a]++ -- | Query a single matching entity.+ -- If there are zero or multiple matching entities, an error will be thrown.+ single :: q i a -> arr i a+ single q =+ all q+ >>> arr+ ( \as -> case as of+ [a] -> a+ _ -> error "TODO"+ )
+ src/Aztecs/ECS/View.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++module Aztecs.ECS.View+ ( View (..),+ view,+ viewSingle,+ filterView,+ unview,+ allDyn,+ singleDyn,+ readAllDyn,+ )+where++import Aztecs.ECS.Query.Dynamic (DynamicQuery (..))+import Aztecs.ECS.Query.Dynamic.Reader (DynamicQueryReader (..))+import Aztecs.ECS.World (World)+import qualified Aztecs.ECS.World as W+import qualified Aztecs.ECS.World.Archetype as A+import Aztecs.ECS.World.Archetypes (ArchetypeID, Archetypes, Node (..))+import qualified Aztecs.ECS.World.Archetypes as AS+import Aztecs.ECS.World.Components (ComponentID)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import Data.Set (Set)++#if !MIN_VERSION_base(4,20,0)+import Data.Foldable (foldl')+#endif++-- | View into a `World`, containing a subset of archetypes.+newtype View = View {viewArchetypes :: Map ArchetypeID Node}+ deriving (Show, Semigroup, Monoid)++-- | View into all archetypes containing the provided component IDs.+view :: Set ComponentID -> Archetypes -> View+view cIds as = View $ AS.lookup cIds as++viewSingle :: Set ComponentID -> Archetypes -> Maybe View+viewSingle cIds as = case Map.toList $ AS.lookup cIds as of+ [a] -> Just . View $ Map.singleton (fst a) (snd a)+ _ -> Nothing++-- | View into all archetypes containing the provided component IDs and matching the provided predicate.+filterView ::+ Set ComponentID ->+ (Node -> Bool) ->+ Archetypes ->+ View+filterView cIds f as = View $ Map.filter f (AS.lookup cIds as)++-- | "Un-view" a `View` back into a `World`.+unview :: View -> World -> World+unview v w =+ w+ { W.archetypes =+ foldl'+ (\as (aId, n) -> as {AS.nodes = Map.insert aId n (AS.nodes as)})+ (W.archetypes w)+ (Map.toList $ viewArchetypes v)+ }++-- | Query all matching entities in a `View`.+allDyn :: i -> DynamicQuery i a -> View -> ([a], View)+allDyn i q v =+ let (as, arches) =+ foldl'+ ( \(acc, archAcc) (aId, n) ->+ let (as', arch') = dynQueryAll q (repeat i) (A.entities (nodeArchetype n)) (nodeArchetype n)+ in (as' ++ acc, Map.insert aId (n {nodeArchetype = arch'}) archAcc)+ )+ ([], Map.empty)+ (Map.toList $ viewArchetypes v)+ in (as, View arches)++-- | Query all matching entities in a `View`.+singleDyn :: i -> DynamicQuery i a -> View -> (Maybe a, View)+singleDyn i q v = case allDyn i q v of+ -- TODO [a], removing this errors for now+ ((a : _), v') -> (Just a, v')+ _ -> (Nothing, v)++-- | Query all matching entities in a `View`.+readAllDyn :: i -> DynamicQueryReader i a -> View -> [a]+readAllDyn i q v =+ foldl'+ ( \acc n ->+ dynQueryReaderAll q (repeat i) (A.entities (nodeArchetype n)) (nodeArchetype n) ++ acc+ )+ []+ (viewArchetypes v)
+ src/Aztecs/ECS/World.hs view
@@ -0,0 +1,245 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++module Aztecs.ECS.World+ ( World (..),+ empty,+ spawn,+ spawnComponent,+ spawnWithId,+ spawnWithArchetypeId,+ spawnEmpty,+ insert,+ insertWithId,+ lookup,+ remove,+ removeWithId,+ despawn,+ )+where++import Aztecs.ECS.Component+ ( Component (..),+ ComponentID,+ )+import Aztecs.ECS.Entity (EntityID (..))+import Aztecs.ECS.World.Archetype (Bundle (..), DynamicBundle (..))+import qualified Aztecs.ECS.World.Archetype as A+import Aztecs.ECS.World.Archetypes (ArchetypeID, Archetypes, Node (..))+import qualified Aztecs.ECS.World.Archetypes as AS+import Aztecs.ECS.World.Components (Components (..))+import qualified Aztecs.ECS.World.Components as CS+import Control.DeepSeq (NFData)+import Data.Dynamic (Dynamic)+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Maybe (fromMaybe)+import qualified Data.Set as Set+import Data.Typeable (Proxy (..), Typeable, typeOf)+import GHC.Generics (Generic)+import Prelude hiding (lookup)++#if !MIN_VERSION_base(4,20,0)+import Data.Foldable (foldl')+#endif++-- | World of entities and their components.+data World = World+ { archetypes :: !Archetypes,+ components :: !Components,+ entities :: !(Map EntityID ArchetypeID),+ nextEntityId :: !EntityID+ }+ deriving (Show, Generic, NFData)++-- | Empty `World`.+empty :: World+empty =+ World+ { archetypes = AS.empty,+ components = CS.empty,+ entities = mempty,+ nextEntityId = EntityID 0+ }++spawn :: Bundle -> World -> (EntityID, World)+spawn b w =+ let (eId, w') = spawnEmpty w+ (cIds, components', dynB) = unBundle b (components w')+ in case AS.lookupArchetypeId cIds (archetypes w') of+ Just aId -> fromMaybe (eId, w') $ do+ node <- AS.lookupNode aId (archetypes w')+ let arch' = runDynamicBundle dynB eId (nodeArchetype node)+ return+ ( eId,+ w'+ { archetypes = (archetypes w') {AS.nodes = Map.insert aId node {nodeArchetype = arch'} (AS.nodes $ archetypes w)},+ components = components',+ entities = Map.insert eId aId (entities w')+ }+ )+ Nothing ->+ let arch' = runDynamicBundle dynB eId A.empty+ (aId, arches) =+ AS.insertArchetype+ cIds+ ( Node+ { nodeComponentIds = cIds,+ nodeArchetype = arch',+ nodeAdd = Map.empty,+ nodeRemove = Map.empty+ }+ )+ (archetypes w')+ in ( eId,+ w'+ { archetypes = arches,+ entities = Map.insert eId aId (entities w'),+ components = components'+ }+ )++-- | Spawn an entity with a component.+spawnComponent :: forall a. (Component a, Typeable (StorageT a)) => a -> World -> (EntityID, World)+spawnComponent c w = case Map.lookup (typeOf (Proxy @a)) (componentIds (components w)) of+ Just cId -> spawnWithId cId c w+ Nothing ->+ let (cId, cs) = CS.insert @a (components w)+ in spawnWithId cId c w {components = cs}++-- | Spawn an empty entity.+spawnEmpty :: World -> (EntityID, World)+spawnEmpty w = let e = nextEntityId w in (e, w {nextEntityId = EntityID (unEntityId e + 1)})++-- | Spawn an entity with a component and its `ComponentID`.+spawnWithId ::+ forall a.+ (Component a, Typeable (StorageT a)) =>+ ComponentID ->+ a ->+ World ->+ (EntityID, World)+spawnWithId cId c w =+ let !(e, w') = spawnEmpty w+ in case AS.lookupArchetypeId (Set.singleton cId) (archetypes w) of+ Just aId -> (e, spawnWithArchetypeId' e aId cId c w')+ Nothing ->+ let !(aId, arches) =+ AS.insertArchetype+ (Set.singleton cId)+ ( Node+ { nodeComponentIds = Set.singleton cId,+ nodeArchetype = A.insertComponent e cId c A.empty,+ nodeAdd = Map.empty,+ nodeRemove = Map.empty+ }+ )+ (archetypes w')+ in (e, w' {archetypes = arches, entities = Map.insert e aId (entities w)})++-- | Spawn an entity with a component and its `ComponentID` directly into an archetype.+spawnWithArchetypeId ::+ forall a.+ (Component a, Typeable (StorageT a)) =>+ a ->+ ComponentID ->+ ArchetypeID ->+ World ->+ (EntityID, World)+spawnWithArchetypeId c cId aId w =+ let !(e, w') = spawnEmpty w+ in (e, spawnWithArchetypeId' e aId cId c w')++spawnWithArchetypeId' ::+ forall a.+ (Component a, Typeable (StorageT a)) =>+ EntityID ->+ ArchetypeID ->+ ComponentID ->+ a ->+ World ->+ World+spawnWithArchetypeId' e aId cId c w =+ let f n = n {nodeArchetype = A.insertComponent e cId c (nodeArchetype n)}+ in w+ { archetypes = (archetypes w) {AS.nodes = Map.adjust f aId (AS.nodes $ archetypes w)},+ entities = Map.insert e aId (entities w)+ }++-- | Insert a component into an entity.+insert :: forall a. (Component a, Typeable (StorageT a)) => EntityID -> a -> World -> World+insert e c w =+ let !(cId, components') = CS.insert @a (components w)+ in insertWithId e cId c w {components = components'}++-- | Insert a component into an entity with its `ComponentID`.+insertWithId :: (Component a, Typeable (StorageT a)) => EntityID -> ComponentID -> a -> World -> World+insertWithId e cId c w = case Map.lookup e (entities w) of+ Just aId ->+ let (maybeNextAId, arches) = AS.insert e aId cId c $ archetypes w+ es = case maybeNextAId of+ Just nextAId -> Map.insert e nextAId (entities w)+ Nothing -> entities w+ in w {archetypes = arches, entities = es}+ Nothing -> case AS.lookupArchetypeId (Set.singleton cId) (archetypes w) of+ Just aId -> spawnWithArchetypeId' e aId cId c w+ Nothing ->+ let (aId, arches) =+ AS.insertArchetype+ (Set.singleton cId)+ ( Node+ { nodeComponentIds = Set.singleton cId,+ nodeArchetype = A.insertComponent e cId c A.empty,+ nodeAdd = Map.empty,+ nodeRemove = Map.empty+ }+ )+ (archetypes w)+ in w {archetypes = arches, entities = Map.insert e aId (entities w)}++lookup :: forall a. (Component a) => EntityID -> World -> Maybe a+lookup e w = do+ !cId <- CS.lookup @a (components w)+ !aId <- Map.lookup e (entities w)+ !node <- AS.lookupNode aId (archetypes w)+ A.lookupComponent e cId (nodeArchetype node)++-- | Insert a component into an entity.+remove :: forall a. (Component a, Typeable (StorageT a)) => EntityID -> World -> (Maybe a, World)+remove e w =+ let !(cId, components') = CS.insert @a (components w)+ in removeWithId @a e cId w {components = components'}++removeWithId :: forall a. (Component a, Typeable (StorageT a)) => EntityID -> ComponentID -> World -> (Maybe a, World)+removeWithId e cId w = case Map.lookup e (entities w) of+ Just aId ->+ let (res, as) = AS.remove @a e aId cId $ archetypes w+ (maybeA, es) = case res of+ Just (a, nextAId) -> (Just a, Map.insert e nextAId (entities w))+ Nothing -> (Nothing, entities w)+ in (maybeA, w {archetypes = as, entities = es})+ Nothing -> (Nothing, w)++-- | Despawn an entity, returning its components.+despawn :: EntityID -> World -> (Map ComponentID Dynamic, World)+despawn e w =+ let res = do+ !aId <- Map.lookup e (entities w)+ !node <- AS.lookupNode aId (archetypes w)+ return (aId, node)+ in case res of+ Just (aId, node) ->+ let !(dynAcc, arch') = A.remove e (nodeArchetype node)+ in ( dynAcc,+ w+ { archetypes = (archetypes w) {AS.nodes = Map.insert aId node {nodeArchetype = arch'} (AS.nodes $ archetypes w)},+ entities = Map.delete e (entities w)+ }+ )+ Nothing -> (Map.empty, w)
+ src/Aztecs/ECS/World/Archetype.hs view
@@ -0,0 +1,218 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++module Aztecs.ECS.World.Archetype+ ( Archetype (..),+ empty,+ all,+ allMaybe,+ entities,+ lookupComponent,+ lookupStorage,+ member,+ remove,+ removeStorages,+ insertComponent,+ insertAscList,+ withAscList,+ Bundle (..),+ bundle,+ runBundle,+ DynamicBundle (..),+ dynBundle,+ AnyStorage (..),+ anyStorage,+ )+where++import Aztecs.ECS.Component (Component (..), ComponentID)+import Aztecs.ECS.Entity (EntityID (..))+import Aztecs.ECS.World.Components (Components)+import qualified Aztecs.ECS.World.Components as CS+import qualified Aztecs.ECS.World.Storage as S+import Control.DeepSeq+import Data.Bifunctor (Bifunctor (..))+import Data.Dynamic (Dynamic, Typeable, fromDynamic, toDyn)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import Data.Maybe (fromMaybe)+import Data.Set (Set)+import qualified Data.Set as Set+import GHC.Generics (Generic)+import Prelude hiding (all, lookup)++#if !MIN_VERSION_base(4,20,0)+import Data.Foldable (foldl')+#endif++data AnyStorage = AnyStorage+ { storageDyn :: !Dynamic,+ insertDyn :: !(Int -> Dynamic -> Dynamic -> Dynamic),+ removeDyn :: !(Int -> Dynamic -> (Maybe Dynamic, Dynamic)),+ removeAny :: !(Int -> Dynamic -> (Maybe AnyStorage, Dynamic)),+ entitiesDyn :: !(Dynamic -> [Int]),+ storageRnf :: !(Dynamic -> ())+ }++instance Show AnyStorage where+ show s = "AnyStorage " ++ show (storageDyn s)++instance NFData AnyStorage where+ rnf s = storageRnf s (storageDyn s)++anyStorage :: forall s a. (S.Storage s a) => s a -> AnyStorage+anyStorage s =+ AnyStorage+ { storageDyn = toDyn s,+ insertDyn = \i cDyn sDyn ->+ fromMaybe sDyn $ do+ !s' <- fromDynamic @(s a) sDyn+ !c <- fromDynamic cDyn+ return . toDyn $ S.insert i c s',+ removeDyn = \i dyn -> case fromDynamic @(s a) dyn of+ Just s' -> let !(a, b) = S.remove i s' in (fmap toDyn a, toDyn b)+ Nothing -> (Nothing, dyn),+ removeAny = \i dyn -> case fromDynamic @(s a) dyn of+ Just s' -> let !(a, b) = S.remove i s' in (fmap (anyStorage . S.singleton @s i) a, toDyn b)+ Nothing -> (Nothing, dyn),+ entitiesDyn = \dyn -> case fromDynamic @(s a) dyn of+ Just s' -> map fst $ S.all s'+ Nothing -> [],+ storageRnf = \dyn -> case fromDynamic @(s a) dyn of+ Just s' -> rnf s'+ Nothing -> ()+ }++newtype Archetype = Archetype {storages :: Map ComponentID AnyStorage}+ deriving (Show, Generic, NFData)++empty :: Archetype+empty = Archetype {storages = Map.empty}++lookupStorage :: (Component a) => ComponentID -> Archetype -> Maybe (StorageT a a)+lookupStorage cId w = do+ dynS <- Map.lookup cId (storages w)+ fromDynamic (storageDyn dynS)++insertComponent :: forall a. (Component a) => EntityID -> ComponentID -> a -> Archetype -> Archetype+insertComponent e cId c arch =+ let !storage = case lookupStorage cId arch of+ Just s -> S.insert (unEntityId e) c s+ Nothing -> S.singleton @(StorageT a) @a (unEntityId e) c+ in arch {storages = Map.insert cId (anyStorage storage) (storages arch)}++all :: (Component a) => ComponentID -> Archetype -> [(EntityID, a)]+all cId arch = fromMaybe [] $ do+ s <- lookupStorage cId arch+ return . map (first EntityID) $ S.all s++member :: ComponentID -> Archetype -> Bool+member cId arch = Map.member cId (storages arch)++allMaybe :: (Component a) => ComponentID -> Archetype -> [(EntityID, Maybe a)]+allMaybe cId arch = case lookupStorage cId arch of+ Just s -> map (\(i, a) -> (EntityID i, Just a)) $ S.all s+ Nothing -> case Map.toList $ storages arch of+ [] -> []+ (_, s) : _ -> map (\i -> (EntityID i, Nothing)) $ entitiesDyn s (storageDyn s)++entities :: Archetype -> [EntityID]+entities arch = case Map.toList $ storages arch of+ [] -> []+ (_, s) : _ -> map (\i -> (EntityID i)) $ entitiesDyn s (storageDyn s)++lookupComponent :: forall a. (Component a) => EntityID -> ComponentID -> Archetype -> Maybe a+lookupComponent e cId w = lookupStorage cId w >>= S.lookup (unEntityId e)++insertAscList :: forall a. (Component a) => ComponentID -> [(EntityID, a)] -> Archetype -> Archetype+insertAscList cId as arch =+ let !storages' =+ Map.insert+ cId+ (anyStorage $ S.fromAscList @(StorageT a) (map (first unEntityId) as))+ (storages arch)+ in arch {storages = storages'}++withAscList :: forall a. (Component a) => ComponentID -> [a] -> Archetype -> Archetype+withAscList cId as arch =+ let !storages' =+ Map.adjust+ ( \s ->+ (anyStorage $ S.fromAscList @(StorageT a) (zip (entitiesDyn s (storageDyn s)) as))+ )+ cId+ (storages arch)+ in arch {storages = storages'}++remove :: EntityID -> Archetype -> (Map ComponentID Dynamic, Archetype)+remove e arch =+ foldl'+ ( \(dynAcc, archAcc) (cId, s) ->+ let !(dynA, dynS) = removeDyn s (unEntityId e) (storageDyn s)+ !dynAcc' = case dynA of+ Just d -> Map.insert cId d dynAcc+ Nothing -> dynAcc+ in ( dynAcc',+ archAcc {storages = Map.insert cId (s {storageDyn = dynS}) (storages archAcc)}+ )+ )+ (Map.empty, arch)+ (Map.toList $ storages arch)++removeStorages :: EntityID -> Archetype -> (Map ComponentID AnyStorage, Archetype)+removeStorages e arch =+ foldl'+ ( \(dynAcc, archAcc) (cId, s) ->+ let (dynA, dynS) = removeAny s (unEntityId e) (storageDyn s)+ dynAcc' = case dynA of+ Just d -> Map.insert cId d dynAcc+ Nothing -> dynAcc+ in ( dynAcc',+ archAcc {storages = Map.insert cId (s {storageDyn = dynS}) (storages archAcc)}+ )+ )+ (Map.empty, arch)+ (Map.toList $ storages arch)++newtype Bundle = Bundle {unBundle :: Components -> (Set ComponentID, Components, DynamicBundle)}++instance Monoid Bundle where+ mempty = Bundle $ \cs -> (Set.empty, cs, mempty)++instance Semigroup Bundle where+ Bundle b1 <> Bundle b2 = Bundle $ \cs ->+ let (cIds1, cs', d1) = b1 cs+ (cIds2, cs'', d2) = b2 cs'+ in (cIds1 <> cIds2, cs'', d1 <> d2)++bundle :: forall a. (Component a, Typeable (StorageT a)) => a -> Bundle+bundle a = Bundle $ \cs ->+ let (cId, cs') = CS.insert @a cs in (Set.singleton cId, cs', dynBundle cId a)++newtype DynamicBundle = DynamicBundle {runDynamicBundle :: EntityID -> Archetype -> Archetype}++instance Semigroup DynamicBundle where+ DynamicBundle d1 <> DynamicBundle d2 = DynamicBundle $ \eId arch -> d2 eId (d1 eId arch)++instance Monoid DynamicBundle where+ mempty = DynamicBundle $ \_ arch -> arch++dynBundle :: (Component a, Typeable (StorageT a)) => ComponentID -> a -> DynamicBundle+dynBundle cId a = DynamicBundle $ \eId arch -> insertComponent eId cId a arch++runBundle :: Bundle -> Components -> EntityID -> Archetype -> (Components, Archetype)+runBundle b cs eId arch =+ let !(_, cs', d) = unBundle b cs+ !arch' = runDynamicBundle d eId arch+ in (cs', arch')
+ src/Aztecs/ECS/World/Archetypes.hs view
@@ -0,0 +1,271 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.ECS.World.Archetypes+ ( ArchetypeID (..),+ Node (..),+ Archetypes (..),+ empty,+ insertArchetype,+ lookupArchetypeId,+ findArchetypeIds,+ lookupNode,+ lookup,+ map,+ adjustArchetype,+ insert,+ remove,+ )+where++import Aztecs.ECS.Component (Component (..), ComponentID)+import Aztecs.ECS.Entity (EntityID (..))+import Aztecs.ECS.World.Archetype+ ( AnyStorage (..),+ Archetype (..),+ insertComponent,+ removeStorages,+ )+import qualified Aztecs.ECS.World.Archetype as A+import Control.DeepSeq (NFData (..))+import Data.Data (Typeable)+import Data.Dynamic (fromDynamic)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import Data.Maybe (mapMaybe)+import Data.Set (Set)+import qualified Data.Set as Set+import GHC.Generics (Generic)+import Prelude hiding (all, lookup, map)++#if !MIN_VERSION_base(4,20,0)+import Data.Foldable (foldl')+#endif++-- | `Archetype` ID.+newtype ArchetypeID = ArchetypeID {unArchetypeId :: Int}+ deriving newtype (Eq, Ord, Show, NFData)++-- | Node in `Archetypes`.+data Node = Node+ { -- | Unique set of `ComponentID`s of this `Node`.+ nodeComponentIds :: !(Set ComponentID),+ -- | `Archetype` of this `Node`.+ nodeArchetype :: !Archetype,+ -- | Edges to other `Archetype`s by adding a `ComponentID`.+ nodeAdd :: !(Map ComponentID ArchetypeID),+ -- | Edges to other `Archetype`s by removing a `ComponentID`.+ nodeRemove :: !(Map ComponentID ArchetypeID)+ }+ deriving (Show, Generic, NFData)++-- | `Archetype` graph.+data Archetypes = Archetypes+ { -- | Archetype nodes in the graph.+ nodes :: !(Map ArchetypeID Node),+ -- | Mapping of unique `ComponentID` sets to `ArchetypeID`s.+ archetypeIds :: !(Map (Set ComponentID) ArchetypeID),+ -- | Next unique `ArchetypeID`.+ nextArchetypeId :: !ArchetypeID,+ -- | Mapping of `ComponentID`s to `ArchetypeID`s of `Archetypes` that contain them.+ componentIds :: !(Map ComponentID (Set ArchetypeID))+ }+ deriving (Show, Generic, NFData)++-- | Empty `Archetypes`.+empty :: Archetypes+empty =+ Archetypes+ { nodes = mempty,+ archetypeIds = mempty,+ nextArchetypeId = ArchetypeID 0,+ componentIds = mempty+ }++-- | Insert an archetype by its set of `ComponentID`s.+insertArchetype :: Set ComponentID -> Node -> Archetypes -> (ArchetypeID, Archetypes)+insertArchetype cIds n arches =+ let aId = nextArchetypeId arches+ in ( aId,+ arches+ { nodes = Map.insert aId n (nodes arches),+ archetypeIds = Map.insert cIds aId (archetypeIds arches),+ nextArchetypeId = ArchetypeID (unArchetypeId aId + 1),+ componentIds = Map.unionWith (<>) (Map.fromSet (const (Set.singleton aId)) cIds) (componentIds arches)+ }+ )++adjustArchetype :: ArchetypeID -> (Archetype -> Archetype) -> Archetypes -> Archetypes+adjustArchetype aId f arches = arches {nodes = Map.adjust (\node -> node {nodeArchetype = f (nodeArchetype node)}) aId (nodes arches)}++-- | Find `ArchetypeID`s containing a set of `ComponentID`s.+findArchetypeIds :: Set ComponentID -> Archetypes -> Set ArchetypeID+findArchetypeIds cIds arches = case mapMaybe (\cId -> Map.lookup cId (componentIds arches)) (Set.elems cIds) of+ (aId : aIds') -> foldl' Set.intersection aId aIds'+ [] -> Set.empty++-- | Lookup `Archetype`s containing a set of `ComponentID`s.+lookup :: Set ComponentID -> Archetypes -> Map ArchetypeID Node+lookup cIds arches =+ Map.fromSet+ (\aId -> nodes arches Map.! aId)+ (findArchetypeIds cIds arches)++-- | Map over `Archetype`s containing a set of `ComponentID`s.+map :: Set ComponentID -> (Archetype -> (a, Archetype)) -> Archetypes -> ([a], Archetypes)+map cIds f arches =+ foldl'+ ( \(acc, archAcc) aId ->+ let !node = nodes archAcc Map.! aId+ !(a, arch') = f (nodeArchetype node)+ in (a : acc, archAcc {nodes = Map.insert aId (node {nodeArchetype = arch'}) (nodes archAcc)})+ )+ ([], arches)+ (findArchetypeIds cIds arches)++lookupArchetypeId :: Set ComponentID -> Archetypes -> Maybe ArchetypeID+lookupArchetypeId cIds arches = Map.lookup cIds (archetypeIds arches)++lookupNode :: ArchetypeID -> Archetypes -> Maybe Node+lookupNode aId arches = Map.lookup aId (nodes arches)++-- | Insert a component into an entity with its `ComponentID`.+insert ::+ (Component a, Typeable (StorageT a)) =>+ EntityID ->+ ArchetypeID ->+ ComponentID ->+ a ->+ Archetypes ->+ (Maybe ArchetypeID, Archetypes)+insert e aId cId c arches = case lookupNode aId arches of+ Just node ->+ if Set.member cId (nodeComponentIds node)+ then (Nothing, arches {nodes = Map.adjust (\n -> n {nodeArchetype = insertComponent e cId c (nodeArchetype n)}) aId (nodes arches)})+ else case lookupArchetypeId (Set.insert cId (nodeComponentIds node)) arches of+ Just nextAId ->+ let !(cs, arch') = A.remove e (nodeArchetype node)+ !arches' = arches {nodes = Map.insert aId node {nodeArchetype = arch'} (nodes arches)}+ f archAcc (itemCId, dyn) =+ archAcc+ { storages =+ Map.adjust+ (\s -> s {storageDyn = insertDyn s (unEntityId e) dyn (storageDyn s)})+ itemCId+ (storages archAcc)+ }+ in ( Just nextAId,+ arches'+ { nodes =+ Map.adjust+ ( \nextNode ->+ nextNode+ { nodeArchetype =+ insertComponent e cId c $+ foldl'+ f+ (nodeArchetype nextNode)+ (Map.toList cs)+ }+ )+ nextAId+ (nodes $ arches')+ }+ )+ Nothing ->+ let !(s, arch') = removeStorages e (nodeArchetype node)+ !n =+ Node+ { nodeComponentIds = Set.insert cId (nodeComponentIds node),+ nodeArchetype = insertComponent e cId c (Archetype {storages = s}),+ nodeAdd = Map.empty,+ nodeRemove = Map.singleton cId aId+ }+ !(nextAId, arches') = insertArchetype (Set.insert cId (nodeComponentIds node)) n arches+ in ( Just nextAId,+ arches'+ { nodes =+ Map.insert+ aId+ node+ { nodeArchetype = arch',+ nodeAdd = Map.insert cId nextAId (nodeAdd node)+ }+ (nodes arches')+ }+ )+ Nothing -> (Nothing, arches)++remove ::+ (Component a, Typeable (StorageT a)) =>+ EntityID ->+ ArchetypeID ->+ ComponentID ->+ Archetypes ->+ (Maybe (a, ArchetypeID), Archetypes)+remove e aId cId arches = case lookupNode aId arches of+ Just node -> case lookupArchetypeId (Set.delete cId (nodeComponentIds node)) arches of+ Just nextAId ->+ let !(cs, arch') = A.remove e (nodeArchetype node)+ !arches' = arches {nodes = Map.insert aId node {nodeArchetype = arch'} (nodes arches)}+ f archAcc (itemCId, dyn) =+ archAcc+ { storages =+ Map.adjust+ (\s -> s {storageDyn = insertDyn s (unEntityId e) dyn (storageDyn s)})+ itemCId+ (storages archAcc)+ }+ (a, cs') = Map.updateLookupWithKey (\_ _ -> Nothing) cId cs+ in ( (,nextAId) <$> (a >>= fromDynamic),+ arches'+ { nodes =+ Map.adjust+ ( \nextNode ->+ nextNode+ { nodeArchetype =+ foldl'+ f+ (nodeArchetype nextNode)+ (Map.toList cs')+ }+ )+ nextAId+ (nodes $ arches')+ }+ )+ Nothing ->+ let !(cs, arch') = removeStorages e (nodeArchetype node)+ (a, cs') = Map.updateLookupWithKey (\_ _ -> Nothing) cId cs+ !n =+ Node+ { nodeComponentIds = Set.insert cId (nodeComponentIds node),+ nodeArchetype = Archetype {storages = cs'},+ nodeAdd = Map.empty,+ nodeRemove = Map.singleton cId aId+ }+ !(nextAId, arches') = insertArchetype (Set.insert cId (nodeComponentIds node)) n arches+ in ( (,nextAId) <$> (a >>= (\a' -> (fst $ A.removeDyn a' (unEntityId e) (A.storageDyn a')) >>= fromDynamic)),+ arches'+ { nodes =+ Map.insert+ aId+ node+ { nodeArchetype = arch',+ nodeAdd = Map.insert cId nextAId (nodeAdd node)+ }+ (nodes arches')+ }+ )+ Nothing -> (Nothing, arches)
+ src/Aztecs/ECS/World/Components.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++module Aztecs.ECS.World.Components+ ( ComponentID (..),+ Components (..),+ empty,+ lookup,+ insert,+ insert',+ )+where++import Aztecs.ECS.Component (Component, ComponentID (..))+import Control.DeepSeq (NFData)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import Data.Typeable (Proxy (..), TypeRep, Typeable, typeOf)+import GHC.Generics (Generic)+import Prelude hiding (lookup)++-- | Component ID map.+data Components = Components+ { componentIds :: !(Map TypeRep ComponentID),+ nextComponentId :: !ComponentID+ }+ deriving (Show, Generic, NFData)++-- | Empty `Components`.+empty :: Components+empty =+ Components+ { componentIds = mempty,+ nextComponentId = ComponentID 0+ }++-- | Lookup a component ID by type.+lookup :: forall a. (Typeable a) => Components -> Maybe ComponentID+lookup cs = Map.lookup (typeOf (Proxy @a)) (componentIds cs)++-- | Insert a component ID by type, if it does not already exist.+insert :: forall a. (Component a) => Components -> (ComponentID, Components)+insert cs = case lookup @a cs of+ Just cId -> (cId, cs)+ Nothing -> insert' @a cs++-- | Insert a component ID by type.+insert' :: forall c. (Component c) => Components -> (ComponentID, Components)+insert' cs =+ let !cId = nextComponentId cs+ in ( cId,+ cs+ { componentIds = Map.insert (typeOf (Proxy @c)) cId (componentIds cs),+ nextComponentId = ComponentID (unComponentId cId + 1)+ }+ )
+ src/Aztecs/ECS/World/Storage.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MonoLocalBinds #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Aztecs.ECS.World.Storage (Storage (..)) where++import Control.DeepSeq (NFData)+import Data.Data (Typeable)+import Data.IntMap.Strict (IntMap)+import qualified Data.IntMap.Strict as IntMap++-- | Component storage, containing zero or many components of the same type.+class (Typeable (s a), NFData (s a), Typeable a) => Storage s a where+ -- | Storage with a single component.+ singleton :: Int -> a -> s a++ -- | All components in the storage.+ all :: s a -> [(Int, a)]++ -- | Insert a component into the storage.+ insert :: Int -> a -> s a -> s a++ -- | Lookup a component in the storage.+ lookup :: Int -> s a -> Maybe a++ -- | Convert a sorted list of components (in ascending order) into a storage.+ fromAscList :: [(Int, a)] -> s a++ -- | Remove a component from the storage.+ remove :: Int -> s a -> (Maybe a, s a)++instance (Typeable a, NFData a) => Storage IntMap a where+ singleton = IntMap.singleton+ all = IntMap.toList+ insert = IntMap.insert+ lookup = IntMap.lookup+ fromAscList = IntMap.fromAscList+ remove i s = (IntMap.lookup i s, IntMap.delete i s) -- TODO remove double lookup
+ src/Aztecs/Hierarchy.hs view
@@ -0,0 +1,175 @@+{-# LANGUAGE Arrows #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeApplications #-}++module Aztecs.Hierarchy+ ( Parent (..),+ Children (..),+ update,+ Hierarchy (..),+ hierarchy,+ hierarchies,+ ParentState (..),+ ChildState (..),+ )+where++import Aztecs+import qualified Aztecs.ECS.Access as A+import Aztecs.ECS.Query (ArrowQuery)+import qualified Aztecs.ECS.Query as Q+import Aztecs.ECS.Query.Reader (ArrowQueryReader)+import Aztecs.ECS.System (ArrowReaderSystem, ArrowSystem)+import qualified Aztecs.ECS.System as S+import Control.Arrow (returnA)+import Control.DeepSeq+import Control.Monad (when)+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Set (Set)+import qualified Data.Set as Set+import GHC.Generics (Generic)++newtype Parent = Parent {unParent :: EntityID}+ deriving (Eq, Ord, Show, Generic, NFData)++instance Component Parent++newtype ParentState = ParentState {unParentState :: EntityID}+ deriving (Show, Generic, NFData)++instance Component ParentState++newtype Children = Children {unChildren :: Set EntityID}+ deriving (Eq, Ord, Show, Semigroup, Monoid, Generic, NFData)++instance Component Children++newtype ChildState = ChildState {unChildState :: Set EntityID}+ deriving (Show, Generic, NFData)++instance Component ChildState++update ::+ (ArrowQueryReader qr, ArrowQuery q, ArrowReaderSystem qr arr, ArrowSystem q arr) =>+ arr () ()+update = proc () -> do+ parents <-+ S.all+ ( proc () -> do+ entity <- Q.entity -< ()+ Parent parent <- Q.fetch -< ()+ maybeParentState <- Q.fetchMaybe @_ @ParentState -< ()+ returnA -< (entity, parent, maybeParentState)+ )+ -<+ ()+ children <-+ S.all+ ( proc () -> do+ entity <- Q.entity -< ()+ Children cs <- Q.fetch -< ()+ maybeChildState <- Q.fetchMaybe @_ @ChildState -< ()+ returnA -< (entity, cs, maybeChildState)+ )+ -<+ ()+ S.queue+ ( \(parents, childRes) -> do+ mapM_+ ( \(entity, parent, maybeParentState) -> case maybeParentState of+ Just (ParentState parentState) -> do+ when (parent /= parentState) $ do+ A.insert parent $ ParentState parent++ -- Remove this entity from the previous parent's children.+ maybeLastChildren <- A.lookup parentState+ let lastChildren = maybe mempty unChildren maybeLastChildren+ let lastChildren' = Set.filter (/= entity) lastChildren+ A.insert parentState . Children $ lastChildren'++ -- Add this entity to the new parent's children.+ maybeChildren <- A.lookup parent+ let parentChildren = maybe mempty unChildren maybeChildren+ A.insert parent . Children $ Set.insert entity parentChildren+ Nothing -> do+ A.spawn_ . bundle $ ParentState parent+ maybeChildren <- A.lookup parent+ let parentChildren = maybe mempty unChildren maybeChildren+ A.insert parent . Children $ Set.insert entity parentChildren+ )+ parents+ mapM_+ ( \(entity, children, maybeChildState) -> case maybeChildState of+ Just (ChildState childState) -> do+ when (children /= childState) $ do+ A.insert entity $ ChildState children+ let added = Set.difference children childState+ -- TODO removed = Set.difference childState children+ mapM_ (\e -> A.insert e . Parent $ entity) added+ Nothing -> do+ A.insert entity $ ChildState children+ mapM_ (\e -> A.insert e . Parent $ entity) children+ )+ childRes+ )+ -<+ (parents, children)++data Hierarchy a = Node+ { nodeEntityId :: EntityID,+ nodeEntity :: a,+ nodeChildren :: [Hierarchy a]+ }++hierarchy ::+ (ArrowQueryReader q, ArrowReaderSystem q arr) =>+ EntityID ->+ q i a ->+ arr i [Hierarchy a]+hierarchy e q = proc i -> do+ children <-+ S.all+ ( proc i -> do+ entity <- Q.entity -< ()+ Children cs <- Q.fetch -< ()+ a <- q -< i+ returnA -< (entity, (cs, a))+ )+ -<+ i+ let childMap = Map.fromList children+ returnA -< hierarchy' e childMap++-- | Build all hierarchies of parents to children with the given query.+hierarchies ::+ (ArrowQueryReader q, ArrowReaderSystem q arr) =>+ q i a ->+ arr i [[Hierarchy a]]+hierarchies q = proc i -> do+ children <-+ S.all+ ( proc i -> do+ entity <- Q.entity -< ()+ Children cs <- Q.fetch -< ()+ a <- q -< i+ returnA -< (entity, (cs, a))+ )+ -<+ i+ let childMap = Map.fromList children+ roots <- S.filter Q.entity $ with @Children <> without @Parent -< ()+ returnA -< map (`hierarchy'` childMap) roots++hierarchy' :: EntityID -> Map EntityID (Set EntityID, a) -> [Hierarchy a]+hierarchy' e childMap = case Map.lookup e childMap of+ Just (cs, a) ->+ let bs = concatMap (`hierarchy'` childMap) (Set.toList cs)+ in [ Node+ { nodeEntityId = e,+ nodeEntity = a,+ nodeChildren = bs+ }+ ]+ Nothing -> []
+ src/Aztecs/Input.hs view
@@ -0,0 +1,205 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}++module Aztecs.Input+ ( Key (..),+ InputMotion (..),+ KeyboardInput (..),+ keyboardInput,+ isKeyPressed,+ wasKeyPressed,+ wasKeyReleased,+ handleKeyboardEvent,+ MouseButton (..),+ MouseInput (..),+ mouseInput,+ handleMouseMotion,+ )+where++import Aztecs.ECS+import Control.DeepSeq (NFData)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import Data.Set (Set)+import qualified Data.Set as Set+import GHC.Generics (Generic)+import Linear (V2 (..))+import Linear.Affine (Point (..))++data Key+ = KeyA+ | KeyB+ | KeyC+ | KeyD+ | KeyE+ | KeyF+ | KeyG+ | KeyH+ | KeyI+ | KeyJ+ | KeyK+ | KeyL+ | KeyM+ | KeyN+ | KeyO+ | KeyP+ | KeyQ+ | KeyR+ | KeyS+ | KeyT+ | KeyU+ | KeyV+ | KeyW+ | KeyX+ | KeyY+ | KeyZ+ | Key0+ | Key1+ | Key2+ | Key3+ | Key4+ | Key5+ | Key6+ | Key7+ | Key8+ | Key9+ | KeyF1+ | KeyF2+ | KeyF3+ | KeyF4+ | KeyF5+ | KeyF6+ | KeyF7+ | KeyF8+ | KeyF9+ | KeyF10+ | KeyF11+ | KeyF12+ | KeyEscape+ | KeyEnter+ | KeySpace+ | KeyBackspace+ | KeyTab+ | KeyCapsLock+ | KeyShift+ | KeyCtrl+ | KeyAlt+ | KeyLeft+ | KeyRight+ | KeyUp+ | KeyDown+ | KeyHome+ | KeyEnd+ | KeyPageUp+ | KeyPageDown+ | KeyInsert+ | KeyDelete+ | KeyMinus+ | KeyEquals+ | KeyBracketLeft+ | KeyBracketRight+ | KeyBackslash+ | KeySemicolon+ | KeyComma+ | KeyPeriod+ | KeySlash+ | KeyNumLock+ | KeyNumpad0+ | KeyNumpad1+ | KeyNumpad2+ | KeyNumpad3+ | KeyNumpad4+ | KeyNumpad5+ | KeyNumpad6+ | KeyNumpad7+ | KeyNumpad8+ | KeyNumpad9+ | KeyNumpadDivide+ | KeyNumpadMultiply+ | KeyNumpadMinus+ | KeyNumpadPlus+ | KeyNumpadEnter+ | KeyNumpadPeriod+ | KeySuper+ | KeyMenu+ deriving (Show, Eq, Ord, Enum, Bounded, Generic, NFData)++-- | Keyboard input component.+data KeyboardInput = KeyboardInput+ { -- | Keyboard events that occured this frame.+ keyboardEvents :: !(Map Key InputMotion),+ -- | Keys that are currently pressed.+ keyboardPressed :: !(Set Key)+ }+ deriving (Show, Generic, NFData)++instance Component KeyboardInput++keyboardInput :: KeyboardInput+keyboardInput = KeyboardInput Map.empty Set.empty++data InputMotion = Pressed | Released+ deriving (Show, Eq, Generic, NFData)++-- | @True@ if this key is currently pressed.+isKeyPressed :: Key -> KeyboardInput -> Bool+isKeyPressed key kb = Set.member key $ keyboardPressed kb++-- | Check for a key event that occured this frame.+keyEvent :: Key -> KeyboardInput -> Maybe InputMotion+keyEvent key kb = Map.lookup key $ keyboardEvents kb++-- | @True@ if this key was pressed this frame.+wasKeyPressed :: Key -> KeyboardInput -> Bool+wasKeyPressed key kb = case keyEvent key kb of+ Just Pressed -> True+ _ -> False++-- | @True@ if this key was released this frame.+wasKeyReleased :: Key -> KeyboardInput -> Bool+wasKeyReleased key kb = case keyEvent key kb of+ Just Released -> True+ _ -> False++handleKeyboardEvent :: Key -> InputMotion -> KeyboardInput -> KeyboardInput+handleKeyboardEvent key motion kb =+ KeyboardInput+ { keyboardEvents = Map.insert key motion $ keyboardEvents kb,+ keyboardPressed = case motion of+ Pressed -> Set.insert key $ keyboardPressed kb+ Released -> Set.delete key $ keyboardPressed kb+ }++data MouseButton+ = ButtonLeft+ | ButtonMiddle+ | ButtonRight+ | ButtonX1+ | ButtonX2+ | -- | An unknown mouse button.+ ButtonExtra !Int+ deriving (Eq, Ord, Show, Generic, NFData)++-- | Mouse input component.+data MouseInput = MouseInput+ { -- | Mouse position in screen-space.+ mousePosition :: !(Point V2 Int),+ -- | Mouse offset since last frame.+ mouseOffset :: !(V2 Int),+ -- | Mouse button states.+ mouseButtons :: !(Map MouseButton InputMotion)+ }+ deriving (Show, Generic, NFData)++instance Component MouseInput++mouseInput :: MouseInput+mouseInput = MouseInput (P 0) (V2 0 0) Map.empty++handleMouseMotion :: V2 Int -> MouseInput -> MouseInput+handleMouseMotion delta mouse =+ mouse+ { mouseOffset = delta,+ mousePosition = mousePosition mouse + P delta+ }
+ src/Aztecs/Time.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Aztecs.Time (Time (..)) where++import Aztecs.ECS+import Control.DeepSeq+import Data.Word (Word32)+import GHC.Generics++newtype Time = Time {elapsedMS :: Word32}+ deriving (Eq, Ord, Num, Show, Generic)++instance Component Time++instance NFData Time where+ rnf = rwhnf
+ src/Aztecs/Transform.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}++module Aztecs.Transform where++import Aztecs.ECS+import Control.DeepSeq+import GHC.Generics (Generic)+import Linear (V2 (..))++data Transform = Transform+ { transformPosition :: !(V2 Int),+ transformRotation :: !Float,+ transformScale :: !(V2 Int)+ }+ deriving (Eq, Show, Generic, NFData)++transform :: Transform+transform = Transform (V2 0 0) 0 (V2 1 1)++instance Component Transform++newtype Size = Size {unSize :: V2 Int}+ deriving (Generic, NFData)++instance Component Size
+ src/Aztecs/Window.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}++module Aztecs.Window (Window (..)) where++import Aztecs.ECS+import Control.DeepSeq (NFData)+import GHC.Generics (Generic)++-- | Window component.+data Window = Window+ { -- | Window title.+ windowTitle :: !String+ }+ deriving (Show, Generic, NFData)++instance Component Window
− src/Data/Aztecs.hs
@@ -1,81 +0,0 @@--- | Aztecs is a type-safe and friendly ECS for games and more.------ An ECS is a modern approach to organizing your application state as a database,--- providing patterns for data-oriented design and parallel processing.------ The ECS architecture is composed of three main concepts:------ === Entities--- An entity is an object comprised of zero or more components.--- In Aztecs, entities are represented by their `EntityID`, a unique identifier.------ === Components--- A `Component` holds the data for a particular aspect of an entity.--- For example, a zombie entity might have a @Health@ and a @Transform@ component.------ > newtype Position = Position Int deriving (Show)--- > instance Component Position--- >--- > newtype Velocity = Velocity Int deriving (Show)--- > instance Component Velocity------ === Systems--- A `System` is a pipeline that processes entities and their components.--- Systems in Aztecs either run in sequence or in parallel automatically based on the components they access.------ Systems can access game state in two ways:------ ==== Access--- An `Access` can be queued for full access to the `World`, after a system is complete.--- `Access` allows for spawning, inserting, and removing components.------ > setup :: System () ()--- > setup = S.queue . const . A.spawn_ $ bundle (Position 0) <> bundle (Velocity 1)------ ==== Queries--- A `Query` can read and write matching components.------ > move :: System () ()--- > move =--- > S.map--- > ( proc () -> do--- > Velocity v <- Q.fetch -< ()--- > Position p <- Q.fetch -< ()--- > Q.set -< Position $ p + v--- > )--- > >>> S.run print------ Finally, systems can be run on a `World` to produce a result.------ > main :: IO ()--- > main = runSystem_ $ setup >>> S.forever move-module Data.Aztecs- ( Access,- runAccess,- Bundle,- bundle,- Component (..),- EntityID,- Query,- QueryFilter,- with,- without,- System,- SystemT,- Schedule,- schedule,- forever,- runSchedule,- runSchedule_,- World,- )-where--import Data.Aztecs.Access (Access, runAccess)-import Data.Aztecs.Component (Component (..))-import Data.Aztecs.Entity (EntityID)-import Data.Aztecs.Query (Query, QueryFilter, with, without)-import Data.Aztecs.Schedule (Schedule, forever, runSchedule, runSchedule_, schedule)-import Data.Aztecs.System (System, SystemT)-import Data.Aztecs.World (World)-import Data.Aztecs.World.Archetype (Bundle, bundle)
− src/Data/Aztecs/Access.hs
@@ -1,69 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}--module Data.Aztecs.Access- ( Access (..),- runAccess,- spawn,- spawn_,- insert,- lookup,- despawn,- )-where--import Control.Monad.IO.Class (MonadIO)-import Control.Monad.State.Strict (MonadState (..), StateT (..))-import Data.Aztecs.Component (Component (..))-import Data.Aztecs.Entity (EntityID (..))-import Data.Aztecs.World (World (..))-import qualified Data.Aztecs.World as W-import Data.Aztecs.World.Archetype (Bundle (..))-import Data.Data (Typeable)-import Prelude hiding (all, lookup, map)---- | Access into the `World`.-newtype Access m a = Access {unAccess :: StateT World m a}- deriving (Functor, Applicative, Monad, MonadIO)---- | Run an `Access` on a `World`, returning the output and updated `World`.-runAccess :: (Functor m) => Access m a -> World -> m (a, World)-runAccess a = runStateT $ unAccess a---- | Spawn an entity with a component.-spawn ::- (Monad m) =>- Bundle ->- Access m EntityID-spawn c = Access $ do- !w <- get- let !(e, w') = W.spawn c w- put w'- return e--spawn_ :: (Monad m) => Bundle -> Access m ()-spawn_ c = do- _ <- spawn c- return ()---- | Insert a component into an entity.-insert :: (Monad m, Component a, Typeable (StorageT a)) => EntityID -> a -> Access m ()-insert e c = Access $ do- !w <- get- let !w' = W.insert e c w- put w'--lookup :: (Monad m, Component a) => EntityID -> Access m (Maybe a)-lookup e = Access $ do- !w <- get- return $ W.lookup e w--despawn :: (Monad m) => EntityID -> Access m ()-despawn e = Access $ do- !w <- get- let !(_, w') = W.despawn e w- put w'
− src/Data/Aztecs/Component.hs
@@ -1,20 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}--module Data.Aztecs.Component (Component (..), ComponentID (..)) where--import Data.Aztecs.Storage (Storage)-import Data.IntMap.Strict (IntMap)-import Data.Kind (Type)-import Data.Typeable (Typeable)---- | Component ID.-newtype ComponentID = ComponentID {unComponentId :: Int}- deriving (Eq, Ord, Show)---- | Component that can be stored in the `World`.-class (Typeable a, Storage (StorageT a) a) => Component a where- -- | `Storage` of this component.- type StorageT a :: Type -> Type-- type StorageT a = IntMap
− src/Data/Aztecs/Entity.hs
@@ -1,5 +0,0 @@-module Data.Aztecs.Entity (EntityID (..)) where---- | Entity ID.-newtype EntityID = EntityID {unEntityId :: Int}- deriving (Eq, Ord, Show)
− src/Data/Aztecs/Query.hs
@@ -1,318 +0,0 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}--module Data.Aztecs.Query- ( -- * Queries- Query (..),- entity,- fetch,- fetchMaybe,- set,- task,- all,-- -- * Filters- QueryFilter (..),- with,- without,- DynamicQueryFilter (..),-- -- * Dynamic queries- DynamicQuery (..),- entityDyn,- fetchDyn,- fetchMaybeDyn,- setDyn,-- -- * Reads and writes- ReadsWrites (..),- disjoint,- )-where--import Control.Arrow (Arrow (..))-import Control.Category (Category (..))-import Control.Monad (mapM)-import Data.Aztecs.Component-import Data.Aztecs.Entity (EntityID)-import Data.Aztecs.World (World (..))-import Data.Aztecs.World.Archetype (Archetype)-import qualified Data.Aztecs.World.Archetype as A-import Data.Aztecs.World.Archetypes (Node (nodeArchetype))-import qualified Data.Aztecs.World.Archetypes as AS-import Data.Aztecs.World.Components (Components)-import qualified Data.Aztecs.World.Components as CS-import qualified Data.Map.Strict as Map-import Data.Set (Set)-import qualified Data.Set as Set-import Prelude hiding (all, any, id, lookup, map, mapM, reads, (.))---- | Query for matching entities.------ === Do notation:--- > move :: (Monad m) => Query m () Position--- > move = proc () -> do--- > Velocity v <- Q.fetch -< ()--- > Position p <- Q.fetch -< ()--- > Q.set -< Position $ p + v------ === Arrow combinators:--- > move :: (Monad m) => Query m () Position--- > move = Q.fetch &&& Q.fetch >>> arr (\(Position p, Velocity v) -> Position $ p + v) >>> Q.set------ === Applicative combinators:--- > move :: (Monad m) => Query m () Position--- > move = (,) <$> Q.fetch <*> Q.fetch >>> arr (\(Position p, Velocity v) -> Position $ p + v) >>> Q.set-newtype Query m i o- = Query {runQuery :: Components -> (ReadsWrites, Components, DynamicQuery m i o)}--instance (Functor m) => Functor (Query m i) where- fmap f (Query q) = Query $ \cs -> let (cIds, cs', qS) = q cs in (cIds, cs', fmap f qS)--instance (Monad m) => Applicative (Query m i) where- pure a = Query $ \cs -> (mempty, cs, pure a)- (Query f) <*> (Query g) = Query $ \cs ->- let (cIdsG, cs', aQS) = g cs- (cIdsF, cs'', bQS) = f cs'- in (cIdsG <> cIdsF, cs'', bQS <*> aQS)--instance (Monad m) => Category (Query m) where- id = Query $ \cs -> (mempty, cs, id)- (Query f) . (Query g) = Query $ \cs ->- let (cIdsG, cs', aQS) = g cs- (cIdsF, cs'', bQS) = f cs'- in (cIdsG <> cIdsF, cs'', bQS . aQS)--instance (Monad m) => Arrow (Query m) where- arr f = Query $ \cs -> (mempty, cs, arr f)- first (Query f) = Query $ \comps -> let (cIds, comps', qS) = f comps in (cIds, comps', first qS)---- | Get the currently matched `EntityID`.-entity :: (Applicative m) => Query m () EntityID-entity = Query $ \cs -> (mempty, cs, entityDyn)---- | Fetch a `Component` by its type.-fetch :: forall m a. (Applicative m, Component a) => Query m () (a)-fetch = Query $ \cs ->- let (cId, cs') = CS.insert @a cs- in (ReadsWrites (Set.singleton cId) (Set.empty), cs', fetchDyn cId)---- | Fetch a `Component` by its type, returning `Nothing` if it doesn't exist.-fetchMaybe :: forall m a. (Applicative m, Component a) => Query m () (Maybe a)-fetchMaybe = Query $ \cs ->- let (cId, cs') = CS.insert @a cs- in (ReadsWrites (Set.singleton cId) (Set.empty), cs', fetchMaybeDyn cId)---- | Set a `Component` by its type.-set :: forall m a. (Applicative m, Component a) => Query m a a-set = Query $ \cs ->- let (cId, cs') = CS.insert @a cs- in (ReadsWrites Set.empty (Set.singleton cId), cs', setDyn cId)---- | Run a monadic task in a `Query`.-task :: (Monad m) => (i -> m o) -> Query m i o-task f = Query $ \cs ->- ( mempty,- cs,- DynamicQuery- { dynQueryAll = \is _ arch -> (,arch) <$> mapM f is,- dynQueryLookup = \i _ arch -> (\a -> (Just a, arch)) <$> f i- }- )---- | Query all matching entities.------ >>> :set -XTypeApplications--- >>> import Data.Aztecs--- >>> import qualified Data.Aztecs.World as W--- >>>--- >>> newtype X = X Int deriving (Show)--- >>> instance Component X--- >>>--- >>> let (_, w) = W.spawn (bundle $ X 0) W.empty--- >>> (xs, _) <- all (fetch @_ @X) w--- >>> xs--- [X 0]-all :: (Monad m) => Query m () a -> World -> m ([a], World)-all q w = do- let (rws, cs', dynQ) = runQuery q (components w)- as <-- mapM- (\n -> fst <$> dynQueryAll dynQ (repeat ()) (A.entities $ nodeArchetype n) (nodeArchetype n))- (Map.elems $ AS.lookup (reads rws <> writes rws) (archetypes w))- return (concat as, w {components = cs'})--data ReadsWrites = ReadsWrites- { reads :: !(Set ComponentID),- writes :: !(Set ComponentID)- }- deriving (Show)--instance Semigroup ReadsWrites where- ReadsWrites r1 w1 <> ReadsWrites r2 w2 = ReadsWrites (r1 <> r2) (w1 <> w2)--instance Monoid ReadsWrites where- mempty = ReadsWrites mempty mempty--disjoint :: ReadsWrites -> ReadsWrites -> Bool-disjoint a b =- Set.disjoint (reads a) (writes b)- || Set.disjoint (reads b) (writes a)- || Set.disjoint (writes b) (writes a)---- | Filter for a `Query`.-newtype QueryFilter = QueryFilter {runQueryFilter :: Components -> (DynamicQueryFilter, Components)}--instance Semigroup QueryFilter where- a <> b =- QueryFilter- ( \cs ->- let (withA', cs') = runQueryFilter a cs- (withB', cs'') = runQueryFilter b cs'- in (withA' <> withB', cs'')- )--instance Monoid QueryFilter where- mempty = QueryFilter (mempty,)---- | Filter for entities containing this component.-with :: forall a. (Component a) => QueryFilter-with = QueryFilter $ \cs ->- let (cId, cs') = CS.insert @a cs in (mempty {filterWith = Set.singleton cId}, cs')---- | Filter out entities containing this component.-without :: forall a. (Component a) => QueryFilter-without = QueryFilter $ \cs ->- let (cId, cs') = CS.insert @a cs in (mempty {filterWithout = Set.singleton cId}, cs')--data DynamicQueryFilter = DynamicQueryFilter- { filterWith :: !(Set ComponentID),- filterWithout :: !(Set ComponentID)- }--instance Semigroup DynamicQueryFilter where- DynamicQueryFilter withA withoutA <> DynamicQueryFilter withB withoutB =- DynamicQueryFilter (withA <> withB) (withoutA <> withoutB)--instance Monoid DynamicQueryFilter where- mempty = DynamicQueryFilter mempty mempty---- | Dynamic query for components by ID.-data DynamicQuery m i o = DynamicQuery- { dynQueryAll :: !([i] -> [EntityID] -> Archetype -> m ([o], Archetype)),- dynQueryLookup :: !(i -> EntityID -> Archetype -> m (Maybe o, Archetype))- }--instance (Functor m) => Functor (DynamicQuery m i) where- fmap f q =- DynamicQuery- { dynQueryAll =- \i es arch -> fmap (\(a, arch') -> (fmap f a, arch')) $ dynQueryAll q i es arch,- dynQueryLookup = \i eId arch -> fmap (first $ fmap f) $ dynQueryLookup q i eId arch- }--instance (Monad m) => Applicative (DynamicQuery m i) where- pure a =- DynamicQuery- { dynQueryAll = \_ es arch -> pure (take (length es) $ repeat a, arch),- dynQueryLookup = \_ _ arch -> pure (Just a, arch)- }- f <*> g =- DynamicQuery- { dynQueryAll = \i es arch -> do- (as, arch') <- dynQueryAll g i es arch- (fs, arch'') <- dynQueryAll f i es arch'- return (zipWith ($) fs as, arch''),- dynQueryLookup = \i eId arch -> do- (res, arch') <- dynQueryLookup g i eId arch- case res of- Just a -> do- (res', arch'') <- dynQueryLookup f i eId arch'- return (fmap ($) res' <*> Just a, arch'')- Nothing -> pure (Nothing, arch')- }--instance (Monad m) => Category (DynamicQuery m) where- id =- DynamicQuery- { dynQueryAll = \as _ arch -> pure (as, arch),- dynQueryLookup = \a _ arch -> pure (Just a, arch)- }- f . g =- DynamicQuery- { dynQueryAll = \i es arch -> do- (as, arch') <- dynQueryAll g i es arch- dynQueryAll f as es arch',- dynQueryLookup = \i eId arch -> do- (res, arch') <- dynQueryLookup g i eId arch- case res of- Just a -> dynQueryLookup f a eId arch'- Nothing -> pure (Nothing, arch')- }--instance (Monad m) => Arrow (DynamicQuery m) where- arr f =- DynamicQuery- { dynQueryAll = \bs _ arch -> pure (fmap f bs, arch),- dynQueryLookup = \b _ arch -> pure (Just (f b), arch)- }- first f =- DynamicQuery- { dynQueryAll = \bds es arch -> do- let (bs, ds) = unzip bds- (cs, arch') <- dynQueryAll f bs es arch- return (zip cs ds, arch'),- dynQueryLookup = \(b, d) eId arch -> do- (res, arch') <- dynQueryLookup f b eId arch- return- ( case res of- Just c -> Just (c, d)- Nothing -> Nothing,- arch'- )- }---- | Fetch the `EntityID` belonging to this entity.-entityDyn :: (Applicative m) => DynamicQuery m i EntityID-entityDyn =- DynamicQuery- { dynQueryAll = \_ es arch -> pure (es, arch),- dynQueryLookup = \_ eId arch -> pure $ (Just eId, arch)- }---- | Fetch an `Component` by its `ComponentID`.-fetchDyn :: forall m a. (Applicative m, Component a) => ComponentID -> DynamicQuery m () a-fetchDyn cId =- DynamicQuery- { dynQueryAll = \_ _ arch -> let !as = A.all cId arch in pure (fmap snd as, arch),- dynQueryLookup = \_ eId arch -> pure $ (A.lookupComponent eId cId arch, arch)- }---- | Fetch an `EntityID` and `Component` by its `ComponentID`.-fetchMaybeDyn ::- forall m a.- (Applicative m, Component a) =>- ComponentID ->- DynamicQuery m () (Maybe a)-fetchMaybeDyn cId =- DynamicQuery- { dynQueryAll = \_ _ arch -> let as = A.allMaybe cId arch in pure (fmap snd as, arch),- dynQueryLookup = \_ eId arch -> pure $ (Just <$> A.lookupComponent eId cId arch, arch)- }---- | Set a `Component` by its `ComponentID`.-setDyn ::- forall m a.- (Applicative m, Component a) =>- ComponentID ->- DynamicQuery m a a-setDyn cId =- DynamicQuery- { dynQueryAll = \is _ arch -> let !arch' = A.withAscList cId is arch in pure (is, arch'),- dynQueryLookup =- \i eId arch -> pure (A.lookupComponent eId cId arch, A.insertComponent eId cId i arch)- }
− src/Data/Aztecs/Schedule.hs
@@ -1,70 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}--module Data.Aztecs.Schedule- ( -- * Schedules- Schedule (..),- schedule,- forever,- runSchedule,- runSchedule_,- )-where--import Control.Arrow (Arrow (..))-import Control.Category (Category (..))-import Control.Monad ((>=>))-import Control.Monad.State (MonadState (..))-import Control.Monad.Trans (MonadTrans (..))-import Data.Aztecs.Access (Access (..), runAccess)-import Data.Aztecs.System (DynamicSystemT (..), SystemT (..))-import qualified Data.Aztecs.View as V-import Data.Aztecs.World (World (..))-import qualified Data.Aztecs.World as W-import Data.Aztecs.World.Components (Components)--newtype Schedule m i o = Schedule {runSchedule' :: Components -> (i -> Access m o, Components)}--instance (Monad m) => Category (Schedule m) where- id = Schedule $ \cs -> (return, cs)- Schedule f . Schedule g = Schedule $ \cs ->- let (g', cs') = g cs- (f', cs'') = f cs'- in (g' >=> f', cs'')--instance Arrow (Schedule IO) where- arr f = Schedule $ \cs -> (return Prelude.. f, cs)- first (Schedule f) = Schedule $ \cs ->- let (g, cs') = f cs- in (\(b, d) -> (,) <$> g b <*> return d, cs')--runSchedule :: (Monad m) => Schedule m i o -> World -> i -> m (o, World)-runSchedule s w i = do- let (f, cs) = runSchedule' s (components w)- (o, w') <- runAccess (f i) w {components = cs}- return (o, w')--runSchedule_ :: (Monad m) => Schedule m () () -> m ()-runSchedule_ s = const () <$> runSchedule s (W.empty) ()--schedule :: (Monad m) => SystemT m i o -> Schedule m i o-schedule t = Schedule $ \cs ->- let (dynT, _, cs') = runSystemT t cs- go i = Access $ do- w <- get- let f = runSystemTDyn dynT w- (o, v, access) <- lift $ f i- ((), w') <- lift Prelude.. runAccess access $ V.unview v w- put w'- return o- in (go, cs')--forever :: (Monad m) => Schedule m i () -> Schedule m i ()-forever s = Schedule $ \cs ->- let (f, cs') = runSchedule' s cs- go i = Access $ do- w <- get- let loop wAcc = do- ((), wAcc') <- lift $ runAccess (f i) wAcc- loop wAcc'- loop w- in (go, cs')
− src/Data/Aztecs/Storage.hs
@@ -1,37 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# LANGUAGE MultiParamTypeClasses #-}--module Data.Aztecs.Storage (Storage (..)) where--import Data.Data (Typeable)-import Data.IntMap.Strict (IntMap)-import qualified Data.IntMap.Strict as IntMap---- | Component storage, containing zero or many components of the same type.-class (Typeable (s a), Typeable a) => Storage s a where- -- | Storage with a single component.- singleton :: Int -> a -> s a-- -- | All components in the storage.- all :: s a -> [(Int, a)]-- -- | Insert a component into the storage.- insert :: Int -> a -> s a -> s a-- -- | Lookup a component in the storage.- lookup :: Int -> s a -> Maybe a-- -- | Convert a sorted list of components (in ascending order) into a storage.- fromAscList :: [(Int, a)] -> s a-- -- | Remove a component from the storage.- remove :: Int -> s a -> (Maybe a, s a)--instance (Typeable a) => Storage IntMap a where- singleton = IntMap.singleton- all = IntMap.toList- insert = IntMap.insert- lookup = IntMap.lookup- fromAscList = IntMap.fromAscList- remove i s = (IntMap.lookup i s, IntMap.delete i s) -- TODO remove double lookup
− src/Data/Aztecs/System.hs
@@ -1,214 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TupleSections #-}--module Data.Aztecs.System- ( -- * Systems- System,- SystemT (..),- queue,- task,-- -- ** Queries-- -- *** Reading- all,- filter,- single,-- -- *** Writing- map,- map_,- filterMap,- mapSingle,-- -- * Dynamic SystemTs- DynamicSystemT (..),- queueDyn,- raceDyn,-- -- ** Queries-- -- *** Reading- allDyn,- filterDyn,- singleDyn,-- -- *** Writing- mapDyn,- filterMapDyn,- )-where--import Control.Arrow (Arrow (..))-import Control.Category (Category (..))-import Control.Concurrent.ParallelIO.Global-import Data.Aztecs.Access (Access (..))-import Data.Aztecs.Component (ComponentID)-import Data.Aztecs.Query (DynamicQuery, DynamicQueryFilter (..), Query (..), QueryFilter (..), ReadsWrites)-import qualified Data.Aztecs.Query as Q-import Data.Aztecs.View (View)-import qualified Data.Aztecs.View as V-import Data.Aztecs.World (World (..))-import qualified Data.Aztecs.World.Archetype as A-import Data.Aztecs.World.Archetypes (Node (..))-import Data.Aztecs.World.Components (Components)-import qualified Data.Foldable as F-import Data.Set (Set)-import Prelude hiding (all, filter, map, (.))-import qualified Prelude hiding (filter, map)--type System i o = SystemT IO i o--newtype SystemT m i o = SystemT {runSystemT :: Components -> (DynamicSystemT m i o, ReadsWrites, Components)}- deriving (Functor)--instance (Monad m) => Category (SystemT m) where- id = SystemT $ \cs -> (DynamicSystemT $ \_ -> \i -> return (i, mempty, pure ()), mempty, cs)- SystemT f . SystemT g = SystemT $ \cs ->- let (f', rwsF, cs') = f cs- (g', rwsG, cs'') = g cs'- in (f' . g', rwsF <> rwsG, cs'')--instance Arrow (SystemT IO) where- arr f = SystemT $ \cs -> (DynamicSystemT $ \_ -> \i -> return (f i, mempty, pure ()), mempty, cs)- first (SystemT f) = SystemT $ \cs ->- let (f', rwsF, cs') = f cs- in (first f', rwsF, cs')- a &&& b = SystemT $ \cs ->- let (dynA, rwsA, cs') = runSystemT a cs- (dynB, rwsB, cs'') = runSystemT b cs'- in ( if Q.disjoint rwsA rwsB- then dynA &&& dynB- else raceDyn dynA dynB,- rwsA <> rwsB,- cs''- )---- | Query all matching entities.-all :: (Monad m) => Query m i a -> SystemT m i [a]-all q = SystemT $ \cs ->- let !(rws, cs', dynQ) = runQuery q cs- in (allDyn (Q.reads rws <> Q.writes rws) dynQ, rws, cs')---- | Query all matching entities with a `QueryFilter`.-filter :: (Monad m) => Query m () a -> QueryFilter -> SystemT m () [a]-filter q qf = SystemT $ \cs ->- let !(rws, cs', dynQ) = runQuery q cs- !(dynQf, cs'') = runQueryFilter qf cs'- qf' n =- F.all (\cId -> A.member cId $ nodeArchetype n) (filterWith dynQf)- && F.all (\cId -> not (A.member cId $ nodeArchetype n)) (filterWithout dynQf)- in (filterDyn (Q.reads rws <> Q.writes rws) dynQ qf', rws, cs'')---- | Query a single matching entity.--- If there are zero or multiple matching entities, an error will be thrown.-single :: (Monad m) => Query m () a -> SystemT m () a-single q =- fmap- ( \as -> case as of- [a] -> a- _ -> error "TODO"- )- (all q)---- | Query all matching entities.-map :: (Monad m) => Query m i a -> SystemT m i [a]-map q = SystemT $ \cs ->- let !(rws, cs', dynQ) = runQuery q cs- in (mapDyn (Q.reads rws <> Q.writes rws) dynQ, rws, cs')--map_ :: (Monad m) => Query m i o -> SystemT m i ()-map_ q = const () <$> map q---- | Map all matching entities with a `QueryFilter`, storing the updated entities.-filterMap :: (Monad m) => Query m i a -> QueryFilter -> SystemT m i [a]-filterMap q qf = SystemT $ \cs ->- let !(rws, cs', dynQ) = runQuery q cs- !(dynQf, cs'') = runQueryFilter qf cs'- f' n =- F.all (\cId -> A.member cId $ nodeArchetype n) (filterWith dynQf)- && F.all (\cId -> not (A.member cId $ nodeArchetype n)) (filterWithout dynQf)- in (filterMapDyn (Q.reads rws <> Q.writes rws) dynQ f', rws, cs'')---- | Map a single matching entity, storing the updated components.--- If there are zero or multiple matching entities, an error will be thrown.-mapSingle :: (Monad m) => Query m i a -> SystemT m i a-mapSingle q =- fmap- ( \as -> case as of- [a] -> a- _ -> error "TODO"- )- (map q)--queue :: (Monad m) => (i -> Access m ()) -> SystemT m i ()-queue f = SystemT $ \cs -> (queueDyn f, mempty, cs)--task :: (Monad m) => (i -> m o) -> SystemT m i o-task f = SystemT $ \cs ->- ( DynamicSystemT $ \_ -> \i -> do- o <- f i- return (o, mempty, pure ()),- mempty,- cs- )--newtype DynamicSystemT m i o = DynamicSystemT {runSystemTDyn :: World -> (i -> m (o, View, Access m ()))}- deriving (Functor)--instance (Monad m) => Category (DynamicSystemT m) where- id = DynamicSystemT $ \_ -> \i -> return (i, mempty, pure ())- DynamicSystemT f . DynamicSystemT g = DynamicSystemT $ \w -> \i -> do- (b, gView, gAccess) <- g w i- (a, fView, fAccess) <- f w b- return (a, gView <> fView, gAccess >> fAccess)--instance (Monad m) => Arrow (DynamicSystemT m) where- arr f = DynamicSystemT $ \_ -> \i -> return (f i, mempty, pure ())- first (DynamicSystemT f) = DynamicSystemT $ \w -> \(i, x) -> do- (a, v, access) <- f w i- return ((a, x), v, access)---- | Query all matching entities.-allDyn :: (Monad m) => Set ComponentID -> DynamicQuery m i o -> DynamicSystemT m i [o]-allDyn cIds q = DynamicSystemT $ \w ->- let !v = V.view cIds $ archetypes w- in \i -> fmap (\(a, _) -> (a, mempty, pure ())) (V.allDyn i q v)--filterDyn :: (Monad m) => Set ComponentID -> DynamicQuery m i o -> (Node -> Bool) -> DynamicSystemT m i [o]-filterDyn cIds q f = DynamicSystemT $ \w ->- let !v = V.filterView cIds f $ archetypes w- in \i -> fmap (\(a, _) -> (a, mempty, pure ())) (V.allDyn i q v)--singleDyn :: (Monad m) => Set ComponentID -> DynamicQuery m () a -> DynamicSystemT m () a-singleDyn cIds q =- fmap- ( \as -> case as of- [a] -> a- _ -> error "TODO"- )- (allDyn cIds q)---- | Map all matching entities, storing the updated entities.-mapDyn :: (Monad m) => Set ComponentID -> DynamicQuery m i o -> DynamicSystemT m i [o]-mapDyn cIds q = DynamicSystemT $ \w ->- let !v = V.view cIds $ archetypes w- in \i -> fmap (\(a, v') -> (a, v', pure ())) (V.allDyn i q v)--filterMapDyn :: (Monad m) => Set ComponentID -> DynamicQuery m i o -> (Node -> Bool) -> DynamicSystemT m i [o]-filterMapDyn cIds q f = DynamicSystemT $ \w ->- let !v = V.filterView cIds f $ archetypes w- in \i -> fmap (\(a, v') -> (a, v', pure ())) (V.allDyn i q v)--queueDyn :: (Monad m) => (i -> Access m ()) -> DynamicSystemT m i ()-queueDyn f = DynamicSystemT $ \_ -> \i -> return ((), mempty, f i)--raceDyn :: DynamicSystemT IO i a -> DynamicSystemT IO i b -> DynamicSystemT IO i (a, b)-raceDyn (DynamicSystemT f) (DynamicSystemT g) = DynamicSystemT $ \w -> \i -> do- results <- parallel [fmap (\a -> (Just a, Nothing)) $ f w i, fmap (\b -> (Nothing, Just b)) $ g w i]- ((a, v, fAccess), (b, v', gAccess)) <- case results of- [(Just a, _), (_, Just b)] -> return (a, b)- _ -> error "joinDyn: exception"- return ((a, b), v <> v', fAccess >> gAccess)
− src/Data/Aztecs/View.hs
@@ -1,70 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}--module Data.Aztecs.View- ( View (..),- view,- filterView,- unview,- allDyn,- )-where--import Data.Aztecs.Query (DynamicQuery (..))-import Data.Aztecs.World (World)-import qualified Data.Aztecs.World as W-import qualified Data.Aztecs.World.Archetype as A-import Data.Aztecs.World.Archetypes (ArchetypeID, Archetypes, Node (..))-import qualified Data.Aztecs.World.Archetypes as AS-import Data.Aztecs.World.Components (ComponentID)-import Data.Foldable (foldlM)-import Data.Map.Strict (Map)-import qualified Data.Map.Strict as Map-import Data.Set (Set)--#if !MIN_VERSION_base(4,20,0)-import Data.Foldable (foldl')-#endif---- | View into a `World`, containing a subset of archetypes.-newtype View = View {viewArchetypes :: Map ArchetypeID Node}- deriving (Show, Semigroup, Monoid)---- | View into all archetypes containing the provided component IDs.-view :: Set ComponentID -> Archetypes -> View-view cIds as = View $ AS.lookup cIds as---- | View into all archetypes containing the provided component IDs and matching the provided predicate.-filterView ::- Set ComponentID ->- (Node -> Bool) ->- Archetypes ->- View-filterView cIds f as = View $ Map.filter f (AS.lookup cIds as)---- | "Un-view" a `View` back into a `World`.-unview :: View -> World -> World-unview v w =- w- { W.archetypes =- foldl'- (\as (aId, n) -> as {AS.nodes = Map.insert aId n (AS.nodes as)})- (W.archetypes w)- (Map.toList $ viewArchetypes v)- }---- | Query all matching entities in a `View`.-allDyn :: (Monad m) => i -> DynamicQuery m i a -> View -> m ([a], View)-allDyn i q v =- fmap (\(as, arches) -> (as, View arches)) $- foldlM- ( \(acc, archAcc) (aId, n) -> do- (as, arch') <- dynQueryAll q (repeat i) (A.entities (nodeArchetype n)) (nodeArchetype n)- return (as ++ acc, Map.insert aId (n {nodeArchetype = arch'}) archAcc)- )- ([], Map.empty)- (Map.toList $ viewArchetypes v)
− src/Data/Aztecs/World.hs
@@ -1,279 +0,0 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE BangPatterns #-}--module Data.Aztecs.World- ( World (..),- empty,- spawn,- spawnComponent,- spawnWithId,- spawnWithArchetypeId,- spawnEmpty,- insert,- insertWithId,- lookup,- despawn,- )-where--import Data.Aztecs.Component- ( Component (..),- ComponentID,- )-import Data.Aztecs.Entity (EntityID (..))-import Data.Aztecs.World.Archetype (Archetype (..), Bundle (..), DynamicBundle (..))-import qualified Data.Aztecs.World.Archetype as A-import Data.Aztecs.World.Archetypes (ArchetypeID, Archetypes, Node (..))-import qualified Data.Aztecs.World.Archetypes as AS-import Data.Aztecs.World.Components (Components (..))-import qualified Data.Aztecs.World.Components as CS-import Data.Dynamic (Dynamic)-import Data.Map (Map)-import qualified Data.Map as Map-import Data.Maybe (fromMaybe)-import qualified Data.Set as Set-import Data.Typeable (Proxy (..), Typeable, typeOf)-import Prelude hiding (lookup)--#if !MIN_VERSION_base(4,20,0)-import Data.Foldable (foldl')-#endif---- | World of entities and their components.-data World = World- { archetypes :: !Archetypes,- components :: !Components,- entities :: !(Map EntityID ArchetypeID),- nextEntityId :: !EntityID- }- deriving (Show)---- | Empty `World`.-empty :: World-empty =- World- { archetypes = AS.empty,- components = CS.empty,- entities = mempty,- nextEntityId = EntityID 0- }--spawn :: Bundle -> World -> (EntityID, World)-spawn b w =- let (eId, w') = spawnEmpty w- (cIds, components', dynB) = unBundle b (components w')- in case AS.lookupArchetypeId cIds (archetypes w') of- Just aId -> fromMaybe (eId, w') $ do- node <- AS.lookupNode aId (archetypes w')- let arch' = runDynamicBundle dynB eId (nodeArchetype node)- return- ( eId,- w'- { archetypes = (archetypes w') {AS.nodes = Map.insert aId node {nodeArchetype = arch'} (AS.nodes $ archetypes w)},- components = components',- entities = Map.insert eId aId (entities w')- }- )- Nothing ->- let arch' = runDynamicBundle dynB eId A.empty- (aId, arches) =- AS.insertArchetype- cIds- ( Node- { nodeComponentIds = cIds,- nodeArchetype = arch',- nodeAdd = Map.empty,- nodeRemove = Map.empty- }- )- (archetypes w')- in ( eId,- w'- { archetypes = arches,- entities = Map.insert eId aId (entities w'),- components = components'- }- )---- | Spawn an entity with a component.-spawnComponent :: forall a. (Component a, Typeable (StorageT a)) => a -> World -> (EntityID, World)-spawnComponent c w = case Map.lookup (typeOf (Proxy @a)) (componentIds (components w)) of- Just cId -> spawnWithId cId c w- Nothing ->- let (cId, cs) = CS.insert @a (components w)- in spawnWithId cId c w {components = cs}---- | Spawn an empty entity.-spawnEmpty :: World -> (EntityID, World)-spawnEmpty w = let e = nextEntityId w in (e, w {nextEntityId = EntityID (unEntityId e + 1)})---- | Spawn an entity with a component and its `ComponentID`.-spawnWithId ::- forall a.- (Component a, Typeable (StorageT a)) =>- ComponentID ->- a ->- World ->- (EntityID, World)-spawnWithId cId c w =- let !(e, w') = spawnEmpty w- in case AS.lookupArchetypeId (Set.singleton cId) (archetypes w) of- Just aId -> (e, spawnWithArchetypeId' e aId cId c w')- Nothing ->- let !(aId, arches) =- AS.insertArchetype- (Set.singleton cId)- ( Node- { nodeComponentIds = Set.singleton cId,- nodeArchetype = A.insertComponent e cId c A.empty,- nodeAdd = Map.empty,- nodeRemove = Map.empty- }- )- (archetypes w')- in (e, w' {archetypes = arches, entities = Map.insert e aId (entities w)})---- | Spawn an entity with a component and its `ComponentID` directly into an archetype.-spawnWithArchetypeId ::- forall a.- (Component a, Typeable (StorageT a)) =>- a ->- ComponentID ->- ArchetypeID ->- World ->- (EntityID, World)-spawnWithArchetypeId c cId aId w =- let !(e, w') = spawnEmpty w- in (e, spawnWithArchetypeId' e aId cId c w')--spawnWithArchetypeId' ::- forall a.- (Component a, Typeable (StorageT a)) =>- EntityID ->- ArchetypeID ->- ComponentID ->- a ->- World ->- World-spawnWithArchetypeId' e aId cId c w =- let f n = n {nodeArchetype = A.insertComponent e cId c (nodeArchetype n)}- in w- { archetypes = (archetypes w) {AS.nodes = Map.adjust f aId (AS.nodes $ archetypes w)},- entities = Map.insert e aId (entities w)- }---- | Insert a component into an entity.-insert :: forall a. (Component a, Typeable (StorageT a)) => EntityID -> a -> World -> World-insert e c w =- let !(cId, components') = CS.insert @a (components w)- in insertWithId e cId c w {components = components'}---- | Insert a component into an entity with its `ComponentID`.-insertWithId :: (Component a, Typeable (StorageT a)) => EntityID -> ComponentID -> a -> World -> World-insertWithId e cId c w = case Map.lookup e (entities w) of- Just aId -> case AS.lookupNode aId (archetypes w) of- Just node ->- if Set.member cId (nodeComponentIds node)- then w {archetypes = (archetypes w) {AS.nodes = Map.adjust (\n -> n {nodeArchetype = A.insertComponent e cId c (nodeArchetype n)}) aId (AS.nodes $ archetypes w)}}- else case AS.lookupArchetypeId (Set.insert cId (nodeComponentIds node)) (archetypes w) of- Just nextAId ->- let !(cs, arch') = A.remove e (nodeArchetype node)- !w' = w {archetypes = (archetypes w) {AS.nodes = Map.insert aId node {nodeArchetype = arch'} (AS.nodes $ archetypes w)}}- f archAcc (itemCId, dyn) =- archAcc- { A.storages =- Map.adjust- (\s -> s {A.storageDyn = A.insertDyn s (unEntityId e) dyn (A.storageDyn s)})- itemCId- (A.storages archAcc)- }- in w'- { archetypes =- (archetypes w')- { AS.nodes =- Map.adjust- ( \nextNode ->- nextNode- { nodeArchetype =- A.insertComponent e cId c $- foldl'- f- (nodeArchetype nextNode)- (Map.toList cs)- }- )- nextAId- (AS.nodes $ archetypes w')- },- entities = Map.insert e nextAId (entities w')- }- Nothing ->- let !(s, arch') = A.removeStorages e (nodeArchetype node)- !n =- Node- { nodeComponentIds = Set.insert cId (nodeComponentIds node),- nodeArchetype = A.insertComponent e cId c (Archetype {A.storages = s}),- nodeAdd = Map.empty,- nodeRemove = Map.singleton cId aId- }- !(nextAId, arches) = AS.insertArchetype (Set.insert cId (nodeComponentIds node)) n (archetypes w)- in w- { archetypes =- arches- { AS.nodes =- Map.insert- aId- node- { nodeArchetype = arch',- nodeAdd = Map.insert cId nextAId (nodeAdd node)- }- (AS.nodes arches)- },- entities = Map.insert e nextAId (entities w)- }- Nothing -> w- Nothing -> case AS.lookupArchetypeId (Set.singleton cId) (archetypes w) of- Just aId -> spawnWithArchetypeId' e aId cId c w- Nothing ->- let (aId, arches) =- AS.insertArchetype- (Set.singleton cId)- ( Node- { nodeComponentIds = Set.singleton cId,- nodeArchetype = A.insertComponent e cId c A.empty,- nodeAdd = Map.empty,- nodeRemove = Map.empty- }- )- (archetypes w)- in w {archetypes = arches, entities = Map.insert e aId (entities w)}--lookup :: forall a. (Component a) => EntityID -> World -> Maybe a-lookup e w = do- !cId <- CS.lookup @a (components w)- !aId <- Map.lookup e (entities w)- !node <- AS.lookupNode aId (archetypes w)- A.lookupComponent e cId (nodeArchetype node)---- | Despawn an entity, returning its components.-despawn :: EntityID -> World -> (Map ComponentID Dynamic, World)-despawn e w =- let res = do- !aId <- Map.lookup e (entities w)- !node <- AS.lookupNode aId (archetypes w)- return (aId, node)- in case res of- Just (aId, node) ->- let !(dynAcc, arch') = A.remove e (nodeArchetype node)- in ( dynAcc,- w- { archetypes = (archetypes w) {AS.nodes = Map.insert aId node {nodeArchetype = arch'} (AS.nodes $ archetypes w)},- entities = Map.delete e (entities w)- }- )- Nothing -> (Map.empty, w)
− src/Data/Aztecs/World/Archetype.hs
@@ -1,207 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}--module Data.Aztecs.World.Archetype- ( Archetype (..),- empty,- all,- allMaybe,- entities,- lookupComponent,- lookupStorage,- member,- remove,- removeStorages,- insertComponent,- insertAscList,- withAscList,- Bundle (..),- bundle,- runBundle,- DynamicBundle (..),- dynBundle,- AnyStorage (..),- anyStorage,- )-where--import Data.Aztecs.Component (Component (..), ComponentID)-import Data.Aztecs.Entity (EntityID (..))-import qualified Data.Aztecs.Storage as S-import Data.Aztecs.World.Components (Components)-import qualified Data.Aztecs.World.Components as CS-import Data.Bifunctor (Bifunctor (..))-import Data.Dynamic (Dynamic, Typeable, fromDynamic, toDyn)-import Data.Map.Strict (Map)-import qualified Data.Map.Strict as Map-import Data.Maybe (fromMaybe)-import Data.Set (Set)-import qualified Data.Set as Set-import Prelude hiding (all, lookup)--#if !MIN_VERSION_base(4,20,0)-import Data.Foldable (foldl')-#endif--data AnyStorage = AnyStorage- { storageDyn :: !Dynamic,- insertDyn :: !(Int -> Dynamic -> Dynamic -> Dynamic),- removeDyn :: !(Int -> Dynamic -> (Maybe Dynamic, Dynamic)),- removeAny :: !(Int -> Dynamic -> (Maybe AnyStorage, Dynamic)),- entitiesDyn :: !(Dynamic -> [Int])- }--instance Show AnyStorage where- show s = "AnyStorage " ++ show (storageDyn s)--anyStorage :: forall s a. (S.Storage s a) => s a -> AnyStorage-anyStorage s =- AnyStorage- { storageDyn = toDyn s,- insertDyn = \i cDyn sDyn ->- fromMaybe sDyn $ do- !s' <- fromDynamic @(s a) sDyn- !c <- fromDynamic cDyn- return . toDyn $ S.insert i c s',- removeDyn = \i dyn -> case fromDynamic @(s a) dyn of- Just s' -> let !(a, b) = S.remove i s' in (fmap toDyn a, toDyn b)- Nothing -> (Nothing, dyn),- removeAny = \i dyn -> case fromDynamic @(s a) dyn of- Just s' -> let !(a, b) = S.remove i s' in (fmap (anyStorage . S.singleton @s i) a, toDyn b)- Nothing -> (Nothing, dyn),- entitiesDyn = \dyn -> case fromDynamic @(s a) dyn of- Just s' -> map fst $ S.all s'- Nothing -> []- }--newtype Archetype = Archetype {storages :: Map ComponentID AnyStorage}- deriving (Show)--empty :: Archetype-empty = Archetype {storages = Map.empty}--lookupStorage :: (Component a) => ComponentID -> Archetype -> Maybe (StorageT a a)-lookupStorage cId w = do- dynS <- Map.lookup cId (storages w)- fromDynamic (storageDyn dynS)--insertComponent :: forall a. (Component a) => EntityID -> ComponentID -> a -> Archetype -> Archetype-insertComponent e cId c arch =- let !storage = case lookupStorage cId arch of- Just s -> S.insert (unEntityId e) c s- Nothing -> S.singleton @(StorageT a) @a (unEntityId e) c- in arch {storages = Map.insert cId (anyStorage storage) (storages arch)}--all :: (Component a) => ComponentID -> Archetype -> [(EntityID, a)]-all cId arch = fromMaybe [] $ do- s <- lookupStorage cId arch- return . map (first EntityID) $ S.all s--member :: ComponentID -> Archetype -> Bool-member cId arch = Map.member cId (storages arch)--allMaybe :: (Component a) => ComponentID -> Archetype -> [(EntityID, Maybe a)]-allMaybe cId arch = case lookupStorage cId arch of- Just s -> map (\(i, a) -> (EntityID i, Just a)) $ S.all s- Nothing -> case Map.toList $ storages arch of- [] -> []- (_, s) : _ -> map (\i -> (EntityID i, Nothing)) $ entitiesDyn s (storageDyn s)--entities :: Archetype -> [EntityID]-entities arch = case Map.toList $ storages arch of- [] -> []- (_, s) : _ -> map (\i -> (EntityID i)) $ entitiesDyn s (storageDyn s)--lookupComponent :: forall a. (Component a) => EntityID -> ComponentID -> Archetype -> Maybe a-lookupComponent e cId w = lookupStorage cId w >>= S.lookup (unEntityId e)--insertAscList :: forall a. (Component a) => ComponentID -> [(EntityID, a)] -> Archetype -> Archetype-insertAscList cId as arch =- let !storages' =- Map.insert- cId- (anyStorage $ S.fromAscList @(StorageT a) (map (first unEntityId) as))- (storages arch)- in arch {storages = storages'}--withAscList :: forall a. (Component a) => ComponentID -> [a] -> Archetype -> Archetype-withAscList cId as arch =- let !storages' =- Map.adjust- ( \s ->- (anyStorage $ S.fromAscList @(StorageT a) (zip (entitiesDyn s (storageDyn s)) as))- )- cId- (storages arch)- in arch {storages = storages'}--remove :: EntityID -> Archetype -> (Map ComponentID Dynamic, Archetype)-remove e arch =- foldl'- ( \(dynAcc, archAcc) (cId, s) ->- let !(dynA, dynS) = removeDyn s (unEntityId e) (storageDyn s)- !dynAcc' = case dynA of- Just d -> Map.insert cId d dynAcc- Nothing -> dynAcc- in ( dynAcc',- archAcc {storages = Map.insert cId (s {storageDyn = dynS}) (storages archAcc)}- )- )- (Map.empty, arch)- (Map.toList $ storages arch)--removeStorages :: EntityID -> Archetype -> (Map ComponentID AnyStorage, Archetype)-removeStorages e arch =- foldl'- ( \(dynAcc, archAcc) (cId, s) ->- let (dynA, dynS) = removeAny s (unEntityId e) (storageDyn s)- dynAcc' = case dynA of- Just d -> Map.insert cId d dynAcc- Nothing -> dynAcc- in ( dynAcc',- archAcc {storages = Map.insert cId (s {storageDyn = dynS}) (storages archAcc)}- )- )- (Map.empty, arch)- (Map.toList $ storages arch)--newtype Bundle = Bundle {unBundle :: Components -> (Set ComponentID, Components, DynamicBundle)}--instance Monoid Bundle where- mempty = Bundle $ \cs -> (Set.empty, cs, mempty)--instance Semigroup Bundle where- Bundle b1 <> Bundle b2 = Bundle $ \cs ->- let (cIds1, cs', d1) = b1 cs- (cIds2, cs'', d2) = b2 cs'- in (cIds1 <> cIds2, cs'', d1 <> d2)--bundle :: forall a. (Component a, Typeable (StorageT a)) => a -> Bundle-bundle a = Bundle $ \cs ->- let (cId, cs') = CS.insert @a cs in (Set.singleton cId, cs', dynBundle cId a)--newtype DynamicBundle = DynamicBundle {runDynamicBundle :: EntityID -> Archetype -> Archetype}--instance Semigroup DynamicBundle where- DynamicBundle d1 <> DynamicBundle d2 = DynamicBundle $ \eId arch -> d2 eId (d1 eId arch)--instance Monoid DynamicBundle where- mempty = DynamicBundle $ \_ arch -> arch--dynBundle :: (Component a, Typeable (StorageT a)) => ComponentID -> a -> DynamicBundle-dynBundle cId a = DynamicBundle $ \eId arch -> insertComponent eId cId a arch--runBundle :: Bundle -> Components -> EntityID -> Archetype -> (Components, Archetype)-runBundle b cs eId arch =- let !(_, cs', d) = unBundle b cs- !arch' = runDynamicBundle d eId arch- in (cs', arch')
− src/Data/Aztecs/World/Archetypes.hs
@@ -1,123 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}--module Data.Aztecs.World.Archetypes- ( ArchetypeID (..),- Node (..),- Archetypes (..),- empty,- insertArchetype,- lookupArchetypeId,- findArchetypeIds,- lookupNode,- lookup,- map,- adjustArchetype,- )-where--import Data.Aztecs.Component (ComponentID)-import Data.Aztecs.World.Archetype hiding (empty)-import Data.Map.Strict (Map)-import qualified Data.Map.Strict as Map-import Data.Maybe (mapMaybe)-import Data.Set (Set)-import qualified Data.Set as Set-import Prelude hiding (all, lookup, map)--#if !MIN_VERSION_base(4,20,0)-import Data.Foldable (foldl')-#endif---- | `Archetype` ID.-newtype ArchetypeID = ArchetypeID {unArchetypeId :: Int}- deriving (Eq, Ord, Show)---- | Node in `Archetypes`.-data Node = Node- { -- | Unique set of `ComponentID`s of this `Node`.- nodeComponentIds :: !(Set ComponentID),- -- | `Archetype` of this `Node`.- nodeArchetype :: !Archetype,- -- | Edges to other `Archetype`s by adding a `ComponentID`.- nodeAdd :: !(Map ComponentID ArchetypeID),- -- | Edges to other `Archetype`s by removing a `ComponentID`.- nodeRemove :: !(Map ComponentID ArchetypeID)- }- deriving (Show)---- | `Archetype` graph.-data Archetypes = Archetypes- { -- | Archetype nodes in the graph.- nodes :: !(Map ArchetypeID Node),- -- | Mapping of unique `ComponentID` sets to `ArchetypeID`s.- archetypeIds :: !(Map (Set ComponentID) ArchetypeID),- -- | Next unique `ArchetypeID`.- nextArchetypeId :: !ArchetypeID,- -- | Mapping of `ComponentID`s to `ArchetypeID`s of `Archetypes` that contain them.- componentIds :: !(Map ComponentID (Set ArchetypeID))- }- deriving (Show)---- | Empty `Archetypes`.-empty :: Archetypes-empty =- Archetypes- { nodes = mempty,- archetypeIds = mempty,- nextArchetypeId = ArchetypeID 0,- componentIds = mempty- }---- | Insert an archetype by its set of `ComponentID`s.-insertArchetype :: Set ComponentID -> Node -> Archetypes -> (ArchetypeID, Archetypes)-insertArchetype cIds n arches =- let aId = nextArchetypeId arches- in ( aId,- arches- { nodes = Map.insert aId n (nodes arches),- archetypeIds = Map.insert cIds aId (archetypeIds arches),- nextArchetypeId = ArchetypeID (unArchetypeId aId + 1),- componentIds = Map.unionWith (<>) (Map.fromSet (const (Set.singleton aId)) cIds) (componentIds arches)- }- )--adjustArchetype :: ArchetypeID -> (Archetype -> Archetype) -> Archetypes -> Archetypes-adjustArchetype aId f arches = arches {nodes = Map.adjust (\node -> node {nodeArchetype = f (nodeArchetype node)}) aId (nodes arches)}---- | Find `ArchetypeID`s containing a set of `ComponentID`s.-findArchetypeIds :: Set ComponentID -> Archetypes -> Set ArchetypeID-findArchetypeIds cIds arches = case mapMaybe (\cId -> Map.lookup cId (componentIds arches)) (Set.elems cIds) of- (aId : aIds') -> foldl' Set.intersection aId aIds'- [] -> Set.empty---- | Lookup `Archetype`s containing a set of `ComponentID`s.-lookup :: Set ComponentID -> Archetypes -> Map ArchetypeID Node-lookup cIds arches =- Map.fromSet- (\aId -> nodes arches Map.! aId)- (findArchetypeIds cIds arches)---- | Map over `Archetype`s containing a set of `ComponentID`s.-map :: Set ComponentID -> (Archetype -> (a, Archetype)) -> Archetypes -> ([a], Archetypes)-map cIds f arches =- foldl'- ( \(acc, archAcc) aId ->- let !node = nodes archAcc Map.! aId- !(a, arch') = f (nodeArchetype node)- in (a : acc, archAcc {nodes = Map.insert aId (node {nodeArchetype = arch'}) (nodes archAcc)})- )- ([], arches)- (findArchetypeIds cIds arches)--lookupArchetypeId :: Set ComponentID -> Archetypes -> Maybe ArchetypeID-lookupArchetypeId cIds arches = Map.lookup cIds (archetypeIds arches)--lookupNode :: ArchetypeID -> Archetypes -> Maybe Node-lookupNode aId arches = Map.lookup aId (nodes arches)
− src/Data/Aztecs/World/Components.hs
@@ -1,56 +0,0 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}--module Data.Aztecs.World.Components- ( ComponentID (..),- Components (..),- empty,- lookup,- insert,- insert',- )-where--import Data.Aztecs.Component (Component, ComponentID (..))-import Data.Map.Strict (Map)-import qualified Data.Map.Strict as Map-import Data.Typeable (Proxy (..), TypeRep, Typeable, typeOf)-import Prelude hiding (lookup)---- | Component ID map.-data Components = Components- { componentIds :: !(Map TypeRep ComponentID),- nextComponentId :: !ComponentID- }- deriving (Show)---- | Empty `Components`.-empty :: Components-empty =- Components- { componentIds = mempty,- nextComponentId = ComponentID 0- }---- | Lookup a component ID by type.-lookup :: forall a. (Typeable a) => Components -> Maybe ComponentID-lookup cs = Map.lookup (typeOf (Proxy @a)) (componentIds cs)---- | Insert a component ID by type, if it does not already exist.-insert :: forall a. (Component a) => Components -> (ComponentID, Components)-insert cs = case lookup @a cs of- Just cId -> (cId, cs)- Nothing -> insert' @a cs---- | Insert a component ID by type.-insert' :: forall c. (Component c) => Components -> (ComponentID, Components)-insert' cs =- let !cId = nextComponentId cs- in ( cId,- cs- { componentIds = Map.insert (typeOf (Proxy @c)) cId (componentIds cs),- nextComponentId = ComponentID (unComponentId cId + 1)- }- )
test/Main.hs view
@@ -1,45 +1,52 @@ {-# LANGUAGE ApplicativeDo #-}+{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Main (main) where +import Aztecs+import qualified Aztecs.ECS.Query as Q+import qualified Aztecs.ECS.World as W+import Aztecs.Hierarchy (Children (..), Parent (..))+import qualified Aztecs.Hierarchy as Hierarchy import Control.Arrow ((&&&))-import Data.Aztecs-import qualified Data.Aztecs.Query as Q-import qualified Data.Aztecs.World as W-import Data.Functor.Identity (Identity (..))+import Control.DeepSeq+import qualified Data.Set as Set+import GHC.Generics import Test.Hspec import Test.QuickCheck -newtype X = X Int deriving (Eq, Show, Arbitrary)+newtype X = X Int deriving (Eq, Show, Arbitrary, Generic, NFData) instance Component X -newtype Y = Y Int deriving (Eq, Show, Arbitrary)+newtype Y = Y Int deriving (Eq, Show, Arbitrary, Generic, NFData) instance Component Y -newtype Z = Z Int deriving (Eq, Show, Arbitrary)+newtype Z = Z Int deriving (Eq, Show, Arbitrary, Generic, NFData) instance Component Z main :: IO () main = hspec $ do- describe "Data.Aztecs.Query.all" $ do+ describe "Aztecs.ECS.Query.all" $ do it "queries a single component" $ property prop_queryOneComponent it "queries two components" $ property prop_queryTwoComponents it "queries three components" $ property prop_queryThreeComponents+ describe "Aztecs.ECS.Hierarchy.update" $ do+ it "adds Parent components to children" $ property prop_addParents prop_queryOneComponent :: [X] -> Expectation prop_queryOneComponent xs = let w = foldr (\x -> snd . W.spawn (bundle x)) W.empty xs- (res, _) = runIdentity $ Q.all Q.fetch w+ (res, _) = Q.all Q.fetch w in res `shouldMatchList` xs prop_queryTwoComponents :: [(X, Y)] -> Expectation prop_queryTwoComponents xys = let w = foldr (\(x, y) -> snd . W.spawn (bundle x <> bundle y)) W.empty xys- (res, _) = runIdentity $ Q.all (Q.fetch &&& Q.fetch) w+ (res, _) = Q.all (Q.fetch &&& Q.fetch) w in res `shouldMatchList` xys prop_queryThreeComponents :: [(X, Y, Z)] -> Expectation@@ -50,5 +57,13 @@ y <- Q.fetch z <- Q.fetch pure (x, y, z)- (res, _) = runIdentity $ Q.all q w+ (res, _) = Q.all q w in res `shouldMatchList` xyzs++prop_addParents :: Expectation+prop_addParents = do+ let (_, w) = W.spawnEmpty W.empty+ (e, w') = W.spawn (bundle . Children $ Set.singleton e) w+ (_, w'') <- runSchedule (system Hierarchy.update) w' ()+ let (res, _) = Q.all Q.fetch w''+ res `shouldMatchList` [Parent e]