aztecs 0.6.0 → 0.7.0
raw patch · 50 files changed
+1557/−953 lines, 50 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Aztecs: [transformPosition] :: Transform -> !V2 Int
- Aztecs: transform :: Transform
- Aztecs.Asset: AssetLoaderT :: StateT (AssetServer a) m o -> AssetLoaderT a m o
- Aztecs.Asset: [unAssetLoader] :: AssetLoaderT a m o -> StateT (AssetServer a) m o
- 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: loadQuery :: (Asset a, ArrowQuery arr) => AssetLoader a o -> arr () o
- Aztecs.Asset: newtype AssetLoaderT a m o
- Aztecs.Asset: type AssetLoader a o = AssetLoaderT a Identity o
- Aztecs.ECS: data Schedule m i o
- Aztecs.ECS: task :: Monad m => (i -> m o) -> Schedule m i o
- Aztecs.ECS.Access: instance GHC.Base.Monad m => Aztecs.ECS.Access.Class.MonadAccess (Aztecs.ECS.Access.AccessT m)
- Aztecs.ECS.Query: entityDyn :: ArrowDynamicQueryReader arr => arr () EntityID
- Aztecs.ECS.Query.Dynamic: entityDyn :: ArrowDynamicQueryReader arr => arr () EntityID
- Aztecs.ECS.Query.Dynamic.Reader: entityDyn :: ArrowDynamicQueryReader arr => arr () EntityID
- Aztecs.ECS.Query.Dynamic.Reader.Class: entityDyn :: ArrowDynamicQueryReader arr => arr () EntityID
- Aztecs.ECS.Query.Reader: Query :: (Components -> (Set ComponentID, Components, DynamicQueryReader i o)) -> QueryReader i o
- Aztecs.ECS.Query.Reader: entityDyn :: ArrowDynamicQueryReader arr => arr () EntityID
- Aztecs.ECS.Query.Reader.Class: entity :: ArrowQueryReader arr => arr () EntityID
- 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: task :: Monad m => (i -> m o) -> Schedule m i o
- Aztecs.ECS.System.Class: queue :: ArrowSystem q arr => (i -> Access ()) -> arr i ()
- 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.Class: filterMapDyn' :: Set ComponentID -> DynamicQuery i o -> (Node -> Bool) -> DynamicSystem i [o]
- Aztecs.ECS.System.Dynamic.Class: mapDyn' :: Set ComponentID -> DynamicQuery i o -> DynamicSystem i [o]
- Aztecs.ECS.System.Dynamic.Class: mapSingleDyn' :: Set ComponentID -> DynamicQuery i o -> DynamicSystem i 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: instance Aztecs.ECS.System.Dynamic.Reader.Class.ArrowDynamicReaderSystem Aztecs.ECS.System.Dynamic.Reader.DynamicReaderSystem
- Aztecs.ECS.System.Reader: filterMap :: ArrowSystem q arr => q i a -> QueryFilter -> arr i [a]
- 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.World: [archetypes] :: World -> !Archetypes
- Aztecs.ECS.World: [components] :: World -> !Components
- Aztecs.ECS.World: spawnComponent :: forall a. (Component a, Typeable (StorageT a)) => a -> 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: 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: [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: instance Control.DeepSeq.NFData Aztecs.ECS.World.Archetype.AnyStorage
- 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.Show.Show Aztecs.ECS.World.Archetype.AnyStorage
- Aztecs.ECS.World.Archetype: newtype Bundle
- Aztecs.ECS.World.Archetype: newtype DynamicBundle
- 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: lookupNode :: ArchetypeID -> Archetypes -> Maybe Node
- Aztecs.ECS.World.Storage: all :: Storage s a => s a -> [(Int, a)]
- Aztecs.Transform: [transformPosition] :: Transform -> !V2 Int
- 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: transform :: Transform
+ Aztecs: Size :: v -> Size v
+ Aztecs: [transformTranslation] :: Transform v r -> !v
+ Aztecs: [unSize] :: Size v -> v
+ Aztecs: newtype Size v
+ Aztecs: size2D :: Size (V2 Integer)
+ Aztecs: transform2d :: Transform2D
+ Aztecs: type Size2D = Size (V2 Int)
+ Aztecs: type Transform2D = Transform (V2 Int) Int
+ Aztecs.Asset.AssetLoader: AssetLoaderT :: StateT (AssetServer a) m o -> AssetLoaderT a m o
+ Aztecs.Asset.AssetLoader: [unAssetLoader] :: AssetLoaderT a m o -> StateT (AssetServer a) m o
+ Aztecs.Asset.AssetLoader: asset :: MonadAssetLoader a m => FilePath -> AssetConfig a -> m (Handle a)
+ Aztecs.Asset.AssetLoader: class MonadAssetLoader a m | m -> a
+ Aztecs.Asset.AssetLoader: instance (GHC.Base.Monad m, Aztecs.Asset.Class.Asset a) => Aztecs.Asset.AssetLoader.Class.MonadAssetLoader a (Aztecs.Asset.AssetLoader.AssetLoaderT a m)
+ Aztecs.Asset.AssetLoader: instance GHC.Base.Functor m => GHC.Base.Functor (Aztecs.Asset.AssetLoader.AssetLoaderT a m)
+ Aztecs.Asset.AssetLoader: instance GHC.Base.Monad m => GHC.Base.Applicative (Aztecs.Asset.AssetLoader.AssetLoaderT a m)
+ Aztecs.Asset.AssetLoader: instance GHC.Base.Monad m => GHC.Base.Monad (Aztecs.Asset.AssetLoader.AssetLoaderT a m)
+ Aztecs.Asset.AssetLoader: load :: (ArrowQuery q, ArrowSystem q arr, Asset a) => AssetLoader a o -> arr () o
+ Aztecs.Asset.AssetLoader: loadQuery :: (Asset a, ArrowQuery arr) => AssetLoader a o -> arr () o
+ Aztecs.Asset.AssetLoader: newtype AssetLoaderT a m o
+ Aztecs.Asset.AssetLoader: type AssetLoader a o = AssetLoaderT a Identity o
+ Aztecs.Asset.AssetLoader.Class: asset :: MonadAssetLoader a m => FilePath -> AssetConfig a -> m (Handle a)
+ Aztecs.Asset.AssetLoader.Class: class MonadAssetLoader a m | m -> a
+ Aztecs.Asset.AssetServer: AssetId :: Int -> AssetId
+ Aztecs.Asset.AssetServer: AssetServer :: !Map AssetId a -> !Map AssetId (Either (IO (IORef (Maybe a))) (IORef (Maybe a))) -> !AssetId -> AssetServer a
+ Aztecs.Asset.AssetServer: Handle :: AssetId -> Handle a
+ Aztecs.Asset.AssetServer: [assetServerAssets] :: AssetServer a -> !Map AssetId a
+ Aztecs.Asset.AssetServer: [handleId] :: Handle a -> AssetId
+ Aztecs.Asset.AssetServer: [loadingAssets] :: AssetServer a -> !Map AssetId (Either (IO (IORef (Maybe a))) (IORef (Maybe a)))
+ Aztecs.Asset.AssetServer: [nextAssetId] :: AssetServer a -> !AssetId
+ Aztecs.Asset.AssetServer: [unAssetId] :: AssetId -> Int
+ Aztecs.Asset.AssetServer: assetServer :: AssetServer a
+ Aztecs.Asset.AssetServer: data AssetServer a
+ Aztecs.Asset.AssetServer: instance Control.DeepSeq.NFData (Aztecs.Asset.AssetServer.AssetServer a)
+ Aztecs.Asset.AssetServer: instance Control.DeepSeq.NFData (Aztecs.Asset.AssetServer.Handle a)
+ Aztecs.Asset.AssetServer: instance Data.Typeable.Internal.Typeable a => Aztecs.ECS.Component.Component (Aztecs.Asset.AssetServer.AssetServer a)
+ Aztecs.Asset.AssetServer: instance GHC.Classes.Eq (Aztecs.Asset.AssetServer.Handle a)
+ Aztecs.Asset.AssetServer: instance GHC.Classes.Eq Aztecs.Asset.AssetServer.AssetId
+ Aztecs.Asset.AssetServer: instance GHC.Classes.Ord (Aztecs.Asset.AssetServer.Handle a)
+ Aztecs.Asset.AssetServer: instance GHC.Classes.Ord Aztecs.Asset.AssetServer.AssetId
+ Aztecs.Asset.AssetServer: instance GHC.Generics.Generic (Aztecs.Asset.AssetServer.AssetServer a)
+ Aztecs.Asset.AssetServer: instance GHC.Show.Show (Aztecs.Asset.AssetServer.Handle a)
+ Aztecs.Asset.AssetServer: instance GHC.Show.Show Aztecs.Asset.AssetServer.AssetId
+ Aztecs.Asset.AssetServer: loadAssets :: forall a qr rs q s b m arr. (Typeable a, ArrowQueryReader qr, ArrowReaderSystem qr rs, ArrowReaderSchedule rs arr, ArrowQuery q, ArrowSystem q s, ArrowSchedule s arr, MonadIO m, ArrowAccessSchedule b m arr) => arr () ()
+ Aztecs.Asset.AssetServer: lookupAsset :: Handle a -> AssetServer a -> Maybe a
+ Aztecs.Asset.AssetServer: newtype AssetId
+ Aztecs.Asset.AssetServer: newtype Handle a
+ Aztecs.Asset.AssetServer: setup :: forall a. Typeable a => System () ()
+ Aztecs.Asset.Class: class (Typeable a) => Asset a where {
+ Aztecs.Asset.Class: loadAsset :: Asset a => FilePath -> AssetConfig a -> IO a
+ Aztecs.Asset.Class: type AssetConfig a;
+ Aztecs.Asset.Class: }
+ Aztecs.ECS: class (MonadAccess b m, Arrow arr) => ArrowAccessSchedule b m arr | arr -> m
+ Aztecs.ECS: class (ArrowDynamicQueryReader arr) => ArrowDynamicQuery arr
+ Aztecs.ECS: class (Arrow arr) => ArrowDynamicQueryReader arr
+ Aztecs.ECS: class (ArrowQueryReader arr) => ArrowQuery arr
+ Aztecs.ECS: class (Arrow arr) => ArrowQueryReader arr
+ Aztecs.ECS: class (MonadAccess b m, Arrow arr) => ArrowQueueSystem b m arr | arr -> m
+ Aztecs.ECS: class (Arrow arr) => ArrowReaderSchedule s arr | arr -> s
+ Aztecs.ECS: class (Arrow arr) => ArrowReaderSystem q arr | arr -> q
+ Aztecs.ECS: class (Arrow arr) => ArrowSchedule s arr | arr -> s
+ Aztecs.ECS: class (Arrow arr) => ArrowSystem q arr | arr -> q
+ Aztecs.ECS: class (Monoid a) => MonoidBundle a
+ Aztecs.ECS: class MonoidDynamicBundle a
+ Aztecs.ECS: data DynamicBundle
+ Aztecs.ECS: delay :: Monad m => a -> Schedule m a a
+ Aztecs.ECS: dynBundle :: (MonoidDynamicBundle a, Component c) => ComponentID -> c -> a
+ Aztecs.ECS: type Schedule m = ScheduleT (AccessT m)
+ Aztecs.ECS.Access: instance Control.Monad.Fix.MonadFix m => Control.Monad.Fix.MonadFix (Aztecs.ECS.Access.AccessT m)
+ Aztecs.ECS.Access: instance GHC.Base.Monad m => Aztecs.ECS.Access.Class.MonadAccess Aztecs.ECS.World.Bundle.Bundle (Aztecs.ECS.Access.AccessT m)
+ Aztecs.ECS.Query: instance Control.Arrow.ArrowChoice Aztecs.ECS.Query.Query
+ Aztecs.ECS.Query.Dynamic: entity :: ArrowDynamicQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query.Dynamic: fromDynReader :: DynamicQueryReader i o -> DynamicQuery i o
+ Aztecs.ECS.Query.Dynamic: instance Control.Arrow.ArrowChoice Aztecs.ECS.Query.Dynamic.DynamicQuery
+ Aztecs.ECS.Query.Dynamic.Reader: entity :: ArrowDynamicQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query.Dynamic.Reader: instance Control.Arrow.ArrowChoice Aztecs.ECS.Query.Dynamic.Reader.DynamicQueryReader
+ Aztecs.ECS.Query.Dynamic.Reader.Class: entity :: ArrowDynamicQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query.Reader: QueryReader :: (Components -> (Set ComponentID, Components, DynamicQueryReader i o)) -> QueryReader i o
+ Aztecs.ECS.Query.Reader: instance Control.Arrow.ArrowChoice Aztecs.ECS.Query.Reader.QueryReader
+ Aztecs.ECS.Schedule: class (MonadAccess b m, Arrow arr) => ArrowAccessSchedule b m arr | arr -> m
+ Aztecs.ECS.Schedule: class (Arrow arr) => ArrowReaderSchedule s arr | arr -> s
+ Aztecs.ECS.Schedule: class (Arrow arr) => ArrowSchedule s arr | arr -> s
+ Aztecs.ECS.Schedule: delay :: Monad m => a -> Schedule m a a
+ Aztecs.ECS.Schedule: instance Control.Monad.Fix.MonadFix m => Control.Arrow.ArrowLoop (Aztecs.ECS.Schedule.ScheduleT m)
+ Aztecs.ECS.Schedule: instance GHC.Base.Functor m => GHC.Base.Functor (Aztecs.ECS.Schedule.ScheduleT m i)
+ Aztecs.ECS.Schedule: instance GHC.Base.Monad m => Aztecs.ECS.Schedule.Access.Class.ArrowAccessSchedule Aztecs.ECS.World.Bundle.Bundle (Aztecs.ECS.Access.AccessT m) (Aztecs.ECS.Schedule.Schedule m)
+ Aztecs.ECS.Schedule: instance GHC.Base.Monad m => Aztecs.ECS.Schedule.Class.ArrowSchedule Aztecs.ECS.System.System (Aztecs.ECS.Schedule.Schedule m)
+ Aztecs.ECS.Schedule: instance GHC.Base.Monad m => Aztecs.ECS.Schedule.Reader.Class.ArrowReaderSchedule Aztecs.ECS.System.Reader.ReaderSystem (Aztecs.ECS.Schedule.Schedule m)
+ Aztecs.ECS.Schedule: instance GHC.Base.Monad m => Control.Arrow.Arrow (Aztecs.ECS.Schedule.ScheduleT m)
+ Aztecs.ECS.Schedule: instance GHC.Base.Monad m => Control.Category.Category (Aztecs.ECS.Schedule.ScheduleT m)
+ Aztecs.ECS.Schedule: newtype ScheduleT m i o
+ Aztecs.ECS.Schedule: type Schedule m = ScheduleT (AccessT m)
+ Aztecs.ECS.Schedule.Access: AcessSchedule :: (i -> AccessT m o) -> AcessSchedule m i o
+ Aztecs.ECS.Schedule.Access: [runAcessSchedule] :: AcessSchedule m i o -> i -> AccessT m o
+ Aztecs.ECS.Schedule.Access: access :: ArrowAccessSchedule b m arr => (i -> m o) -> arr i o
+ Aztecs.ECS.Schedule.Access: class (MonadAccess b m, Arrow arr) => ArrowAccessSchedule b m arr | arr -> m
+ Aztecs.ECS.Schedule.Access: instance GHC.Base.Functor m => GHC.Base.Functor (Aztecs.ECS.Schedule.Access.AcessSchedule m i)
+ Aztecs.ECS.Schedule.Access: instance GHC.Base.Monad m => Aztecs.ECS.Schedule.Access.Class.ArrowAccessSchedule Aztecs.ECS.World.Bundle.Bundle (Aztecs.ECS.Access.AccessT m) (Aztecs.ECS.Schedule.Access.AcessSchedule m)
+ Aztecs.ECS.Schedule.Access: instance GHC.Base.Monad m => Control.Arrow.Arrow (Aztecs.ECS.Schedule.Access.AcessSchedule m)
+ Aztecs.ECS.Schedule.Access: instance GHC.Base.Monad m => Control.Category.Category (Aztecs.ECS.Schedule.Access.AcessSchedule m)
+ Aztecs.ECS.Schedule.Access: newtype AcessSchedule m i o
+ Aztecs.ECS.Schedule.Access.Class: access :: ArrowAccessSchedule b m arr => (i -> m o) -> arr i o
+ Aztecs.ECS.Schedule.Access.Class: class (MonadAccess b m, Arrow arr) => ArrowAccessSchedule b m arr | arr -> m
+ Aztecs.ECS.Schedule.Class: class (Arrow arr) => ArrowSchedule s arr | arr -> s
+ Aztecs.ECS.Schedule.Class: system :: ArrowSchedule s arr => s i o -> arr i o
+ Aztecs.ECS.Schedule.Dynamic: DynamicSchedule :: (i -> m (o, DynamicScheduleT m i o)) -> DynamicScheduleT m i o
+ Aztecs.ECS.Schedule.Dynamic: [runScheduleDyn] :: DynamicScheduleT m i o -> i -> m (o, DynamicScheduleT m i o)
+ Aztecs.ECS.Schedule.Dynamic: instance Control.Monad.Fix.MonadFix m => Control.Arrow.ArrowLoop (Aztecs.ECS.Schedule.Dynamic.DynamicScheduleT m)
+ Aztecs.ECS.Schedule.Dynamic: instance GHC.Base.Functor m => GHC.Base.Functor (Aztecs.ECS.Schedule.Dynamic.DynamicScheduleT m i)
+ Aztecs.ECS.Schedule.Dynamic: instance GHC.Base.Monad m => Control.Arrow.Arrow (Aztecs.ECS.Schedule.Dynamic.DynamicScheduleT m)
+ Aztecs.ECS.Schedule.Dynamic: instance GHC.Base.Monad m => Control.Arrow.ArrowChoice (Aztecs.ECS.Schedule.Dynamic.DynamicScheduleT m)
+ Aztecs.ECS.Schedule.Dynamic: instance GHC.Base.Monad m => Control.Category.Category (Aztecs.ECS.Schedule.Dynamic.DynamicScheduleT m)
+ Aztecs.ECS.Schedule.Dynamic: newtype DynamicScheduleT m i o
+ Aztecs.ECS.Schedule.Dynamic: type DynamicSchedule m = DynamicScheduleT (AccessT m)
+ Aztecs.ECS.Schedule.Dynamic.Reader: DynamicReaderSchedule :: (i -> m (o, DynamicReaderScheduleT m i o)) -> DynamicReaderScheduleT m i o
+ Aztecs.ECS.Schedule.Dynamic.Reader: [runScheduleDyn] :: DynamicReaderScheduleT m i o -> i -> m (o, DynamicReaderScheduleT m i o)
+ Aztecs.ECS.Schedule.Dynamic.Reader: instance Control.Monad.Fix.MonadFix m => Control.Arrow.ArrowLoop (Aztecs.ECS.Schedule.Dynamic.Reader.DynamicReaderScheduleT m)
+ Aztecs.ECS.Schedule.Dynamic.Reader: instance GHC.Base.Functor m => GHC.Base.Functor (Aztecs.ECS.Schedule.Dynamic.Reader.DynamicReaderScheduleT m i)
+ Aztecs.ECS.Schedule.Dynamic.Reader: instance GHC.Base.Monad m => Control.Arrow.Arrow (Aztecs.ECS.Schedule.Dynamic.Reader.DynamicReaderScheduleT m)
+ Aztecs.ECS.Schedule.Dynamic.Reader: instance GHC.Base.Monad m => Control.Arrow.ArrowChoice (Aztecs.ECS.Schedule.Dynamic.Reader.DynamicReaderScheduleT m)
+ Aztecs.ECS.Schedule.Dynamic.Reader: instance GHC.Base.Monad m => Control.Category.Category (Aztecs.ECS.Schedule.Dynamic.Reader.DynamicReaderScheduleT m)
+ Aztecs.ECS.Schedule.Dynamic.Reader: newtype DynamicReaderScheduleT m i o
+ Aztecs.ECS.Schedule.Dynamic.Reader: type DynamicReaderSchedule m = DynamicReaderScheduleT (AccessT m)
+ Aztecs.ECS.Schedule.Reader: ReaderSchedule :: (Components -> (DynamicReaderScheduleT m i o, Components)) -> ReaderScheduleT m i o
+ Aztecs.ECS.Schedule.Reader: [runReaderSchedule] :: ReaderScheduleT m i o -> Components -> (DynamicReaderScheduleT m i o, Components)
+ Aztecs.ECS.Schedule.Reader: instance Control.Monad.Fix.MonadFix m => Control.Arrow.ArrowLoop (Aztecs.ECS.Schedule.Reader.ReaderScheduleT m)
+ Aztecs.ECS.Schedule.Reader: instance GHC.Base.Functor m => GHC.Base.Functor (Aztecs.ECS.Schedule.Reader.ReaderScheduleT m i)
+ Aztecs.ECS.Schedule.Reader: instance GHC.Base.Monad m => Aztecs.ECS.Schedule.Reader.Class.ArrowReaderSchedule Aztecs.ECS.System.Reader.ReaderSystem (Aztecs.ECS.Schedule.Reader.ReaderSchedule m)
+ Aztecs.ECS.Schedule.Reader: instance GHC.Base.Monad m => Control.Arrow.Arrow (Aztecs.ECS.Schedule.Reader.ReaderScheduleT m)
+ Aztecs.ECS.Schedule.Reader: instance GHC.Base.Monad m => Control.Arrow.ArrowChoice (Aztecs.ECS.Schedule.Reader.ReaderScheduleT m)
+ Aztecs.ECS.Schedule.Reader: instance GHC.Base.Monad m => Control.Category.Category (Aztecs.ECS.Schedule.Reader.ReaderScheduleT m)
+ Aztecs.ECS.Schedule.Reader: newtype ReaderScheduleT m i o
+ Aztecs.ECS.Schedule.Reader.Class: class (Arrow arr) => ArrowReaderSchedule s arr | arr -> s
+ Aztecs.ECS.Schedule.Reader.Class: reader :: ArrowReaderSchedule s arr => s i o -> arr i o
+ Aztecs.ECS.System: class (MonadAccess b m, Arrow arr) => ArrowQueueSystem b m arr | arr -> m
+ Aztecs.ECS.System: fromReader :: ReaderSystem i o -> System i o
+ Aztecs.ECS.System: instance Aztecs.ECS.System.Queue.Class.ArrowQueueSystem Aztecs.ECS.World.Bundle.Bundle Aztecs.ECS.Access.Access Aztecs.ECS.System.System
+ Aztecs.ECS.System: instance Control.Arrow.ArrowChoice Aztecs.ECS.System.System
+ Aztecs.ECS.System: instance Control.Arrow.ArrowLoop Aztecs.ECS.System.System
+ Aztecs.ECS.System.Dynamic: allDyn :: ArrowDynamicReaderSystem q arr => Set ComponentID -> q i o -> arr i [o]
+ Aztecs.ECS.System.Dynamic: class (Arrow arr) => ArrowDynamicReaderSystem q arr | arr -> q
+ Aztecs.ECS.System.Dynamic: class ArrowDynamicSystem q arr | arr -> q
+ Aztecs.ECS.System.Dynamic: class (MonadAccess b m, Arrow arr) => ArrowQueueSystem b m arr | arr -> m
+ Aztecs.ECS.System.Dynamic: filterDyn :: ArrowDynamicReaderSystem q arr => Set ComponentID -> q i o -> (Node -> Bool) -> arr i [o]
+ Aztecs.ECS.System.Dynamic: filterMapDyn :: ArrowDynamicSystem q arr => Set ComponentID -> q i o -> (Node -> Bool) -> arr i [o]
+ Aztecs.ECS.System.Dynamic: fromDynReaderSystem :: DynamicReaderSystem i o -> DynamicSystem i o
+ Aztecs.ECS.System.Dynamic: instance Aztecs.ECS.System.Dynamic.Class.ArrowDynamicSystem Aztecs.ECS.Query.Dynamic.DynamicQuery Aztecs.ECS.System.Dynamic.DynamicSystem
+ Aztecs.ECS.System.Dynamic: instance Aztecs.ECS.System.Dynamic.Reader.Class.ArrowDynamicReaderSystem Aztecs.ECS.Query.Dynamic.Reader.DynamicQueryReader Aztecs.ECS.System.Dynamic.DynamicSystem
+ Aztecs.ECS.System.Dynamic: instance Aztecs.ECS.System.Queue.Class.ArrowQueueSystem Aztecs.ECS.World.Bundle.Bundle Aztecs.ECS.Access.Access Aztecs.ECS.System.Dynamic.DynamicSystem
+ Aztecs.ECS.System.Dynamic: instance Control.Arrow.ArrowChoice Aztecs.ECS.System.Dynamic.DynamicSystem
+ Aztecs.ECS.System.Dynamic: instance Control.Arrow.ArrowLoop Aztecs.ECS.System.Dynamic.DynamicSystem
+ Aztecs.ECS.System.Dynamic: mapDyn :: ArrowDynamicSystem q arr => Set ComponentID -> q i o -> arr i [o]
+ Aztecs.ECS.System.Dynamic: mapSingleDyn :: ArrowDynamicSystem q arr => Set ComponentID -> q i o -> arr i o
+ Aztecs.ECS.System.Dynamic: mapSingleMaybeDyn :: ArrowDynamicSystem q arr => Set ComponentID -> q i o -> arr i (Maybe o)
+ Aztecs.ECS.System.Dynamic: queue :: ArrowQueueSystem b m arr => (i -> m ()) -> arr i ()
+ Aztecs.ECS.System.Dynamic: singleDyn :: ArrowDynamicReaderSystem q arr => Set ComponentID -> q () a -> arr () a
+ Aztecs.ECS.System.Dynamic.Reader: class (MonadAccess b m, Arrow arr) => ArrowQueueSystem b m arr | arr -> m
+ Aztecs.ECS.System.Dynamic.Reader: instance Aztecs.ECS.System.Dynamic.Reader.Class.ArrowDynamicReaderSystem Aztecs.ECS.Query.Dynamic.Reader.DynamicQueryReader Aztecs.ECS.System.Dynamic.Reader.DynamicReaderSystem
+ Aztecs.ECS.System.Dynamic.Reader: instance Aztecs.ECS.System.Queue.Class.ArrowQueueSystem Aztecs.ECS.World.Bundle.Bundle Aztecs.ECS.Access.Access Aztecs.ECS.System.Dynamic.Reader.DynamicReaderSystem
+ Aztecs.ECS.System.Dynamic.Reader: instance Control.Arrow.ArrowChoice Aztecs.ECS.System.Dynamic.Reader.DynamicReaderSystem
+ Aztecs.ECS.System.Dynamic.Reader: instance Control.Arrow.ArrowLoop Aztecs.ECS.System.Dynamic.Reader.DynamicReaderSystem
+ Aztecs.ECS.System.Dynamic.Reader: queue :: ArrowQueueSystem b m arr => (i -> m ()) -> arr i ()
+ Aztecs.ECS.System.Queue: QueueSystem :: (i -> (o, Access ())) -> QueueSystem i o
+ Aztecs.ECS.System.Queue: [runQueueSystem] :: QueueSystem i o -> i -> (o, Access ())
+ Aztecs.ECS.System.Queue: class (MonadAccess b m, Arrow arr) => ArrowQueueSystem b m arr | arr -> m
+ Aztecs.ECS.System.Queue: instance Aztecs.ECS.System.Queue.Class.ArrowQueueSystem Aztecs.ECS.World.Bundle.Bundle Aztecs.ECS.Access.Access Aztecs.ECS.System.Queue.QueueSystem
+ Aztecs.ECS.System.Queue: instance Control.Arrow.Arrow Aztecs.ECS.System.Queue.QueueSystem
+ Aztecs.ECS.System.Queue: instance Control.Category.Category Aztecs.ECS.System.Queue.QueueSystem
+ Aztecs.ECS.System.Queue: instance GHC.Base.Functor (Aztecs.ECS.System.Queue.QueueSystem i)
+ Aztecs.ECS.System.Queue: newtype QueueSystem i o
+ Aztecs.ECS.System.Queue: queue :: ArrowQueueSystem b m arr => (i -> m ()) -> arr i ()
+ Aztecs.ECS.System.Queue.Class: class (MonadAccess b m, Arrow arr) => ArrowQueueSystem b m arr | arr -> m
+ Aztecs.ECS.System.Queue.Class: queue :: ArrowQueueSystem b m arr => (i -> m ()) -> arr i ()
+ Aztecs.ECS.System.Reader: class (MonadAccess b m, Arrow arr) => ArrowQueueSystem b m arr | arr -> m
+ Aztecs.ECS.System.Reader: class (Arrow arr) => ArrowReaderSystem q arr | arr -> q
+ Aztecs.ECS.System.Reader: instance Aztecs.ECS.System.Queue.Class.ArrowQueueSystem Aztecs.ECS.World.Bundle.Bundle Aztecs.ECS.Access.Access Aztecs.ECS.System.Reader.ReaderSystem
+ Aztecs.ECS.System.Reader: instance Control.Arrow.ArrowChoice Aztecs.ECS.System.Reader.ReaderSystem
+ Aztecs.ECS.System.Reader: instance Control.Arrow.ArrowLoop Aztecs.ECS.System.Reader.ReaderSystem
+ Aztecs.ECS.World.Archetypes: find :: Set ComponentID -> Archetypes -> Map ArchetypeID Node
+ Aztecs.ECS.World.Bundle: Bundle :: (Components -> (Set ComponentID, Components, DynamicBundle)) -> Bundle
+ Aztecs.ECS.World.Bundle: [unBundle] :: Bundle -> Components -> (Set ComponentID, Components, DynamicBundle)
+ Aztecs.ECS.World.Bundle: bundle :: forall c. (MonoidBundle a, Component c) => c -> a
+ Aztecs.ECS.World.Bundle: class (Monoid a) => MonoidBundle a
+ Aztecs.ECS.World.Bundle: class MonoidDynamicBundle a
+ Aztecs.ECS.World.Bundle: dynBundle :: (MonoidDynamicBundle a, Component c) => ComponentID -> c -> a
+ Aztecs.ECS.World.Bundle: instance Aztecs.ECS.World.Bundle.Class.MonoidBundle Aztecs.ECS.World.Bundle.Bundle
+ Aztecs.ECS.World.Bundle: instance Aztecs.ECS.World.Bundle.Dynamic.Class.MonoidDynamicBundle Aztecs.ECS.World.Bundle.Bundle
+ Aztecs.ECS.World.Bundle: instance GHC.Base.Monoid Aztecs.ECS.World.Bundle.Bundle
+ Aztecs.ECS.World.Bundle: instance GHC.Base.Semigroup Aztecs.ECS.World.Bundle.Bundle
+ Aztecs.ECS.World.Bundle: newtype Bundle
+ Aztecs.ECS.World.Bundle: runBundle :: Bundle -> Components -> EntityID -> Archetype -> (Components, Archetype)
+ Aztecs.ECS.World.Bundle.Class: bundle :: forall c. (MonoidBundle a, Component c) => c -> a
+ Aztecs.ECS.World.Bundle.Class: class (Monoid a) => MonoidBundle a
+ Aztecs.ECS.World.Bundle.Dynamic: DynamicBundle :: (EntityID -> Archetype -> Archetype) -> DynamicBundle
+ Aztecs.ECS.World.Bundle.Dynamic: [runDynamicBundle] :: DynamicBundle -> EntityID -> Archetype -> Archetype
+ Aztecs.ECS.World.Bundle.Dynamic: class MonoidDynamicBundle a
+ Aztecs.ECS.World.Bundle.Dynamic: dynBundle :: (MonoidDynamicBundle a, Component c) => ComponentID -> c -> a
+ Aztecs.ECS.World.Bundle.Dynamic: instance Aztecs.ECS.World.Bundle.Dynamic.Class.MonoidDynamicBundle Aztecs.ECS.World.Bundle.Dynamic.DynamicBundle
+ Aztecs.ECS.World.Bundle.Dynamic: instance GHC.Base.Monoid Aztecs.ECS.World.Bundle.Dynamic.DynamicBundle
+ Aztecs.ECS.World.Bundle.Dynamic: instance GHC.Base.Semigroup Aztecs.ECS.World.Bundle.Dynamic.DynamicBundle
+ Aztecs.ECS.World.Bundle.Dynamic: newtype DynamicBundle
+ Aztecs.ECS.World.Bundle.Dynamic.Class: class MonoidDynamicBundle a
+ Aztecs.ECS.World.Bundle.Dynamic.Class: dynBundle :: (MonoidDynamicBundle a, Component c) => ComponentID -> c -> a
+ Aztecs.ECS.World.Entities: Entities :: !Archetypes -> !Components -> !Map EntityID ArchetypeID -> Entities
+ Aztecs.ECS.World.Entities: [archetypes] :: Entities -> !Archetypes
+ Aztecs.ECS.World.Entities: [components] :: Entities -> !Components
+ Aztecs.ECS.World.Entities: [entities] :: Entities -> !Map EntityID ArchetypeID
+ Aztecs.ECS.World.Entities: data Entities
+ Aztecs.ECS.World.Entities: despawn :: EntityID -> Entities -> (Map ComponentID Dynamic, Entities)
+ Aztecs.ECS.World.Entities: empty :: Entities
+ Aztecs.ECS.World.Entities: insert :: forall a. Component a => EntityID -> a -> Entities -> Entities
+ Aztecs.ECS.World.Entities: insertWithId :: Component a => EntityID -> ComponentID -> a -> Entities -> Entities
+ Aztecs.ECS.World.Entities: instance Control.DeepSeq.NFData Aztecs.ECS.World.Entities.Entities
+ Aztecs.ECS.World.Entities: instance GHC.Generics.Generic Aztecs.ECS.World.Entities.Entities
+ Aztecs.ECS.World.Entities: instance GHC.Show.Show Aztecs.ECS.World.Entities.Entities
+ Aztecs.ECS.World.Entities: lookup :: forall a. Component a => EntityID -> Entities -> Maybe a
+ Aztecs.ECS.World.Entities: remove :: forall a. Component a => EntityID -> Entities -> (Maybe a, Entities)
+ Aztecs.ECS.World.Entities: removeWithId :: forall a. Component a => EntityID -> ComponentID -> Entities -> (Maybe a, Entities)
+ Aztecs.ECS.World.Entities: spawn :: EntityID -> Bundle -> Entities -> Entities
+ Aztecs.ECS.World.Entities: spawnComponent :: forall a. Component a => EntityID -> a -> Entities -> Entities
+ Aztecs.ECS.World.Entities: spawnWithArchetypeId :: forall a. Component a => EntityID -> ArchetypeID -> ComponentID -> a -> Entities -> Entities
+ Aztecs.ECS.World.Entities: spawnWithId :: forall a. Component a => EntityID -> ComponentID -> a -> Entities -> Entities
+ Aztecs.ECS.World.Storage: toList :: Storage s a => s a -> [(Int, a)]
+ Aztecs.ECS.World.Storage.Dynamic: DynamicStorage :: !Dynamic -> !Int -> Dynamic -> Dynamic -> Dynamic -> !Int -> Dynamic -> (Maybe Dynamic, Dynamic) -> !Int -> Dynamic -> (Maybe DynamicStorage, Dynamic) -> !Dynamic -> [Int] -> !Dynamic -> () -> DynamicStorage
+ Aztecs.ECS.World.Storage.Dynamic: [entitiesDyn'] :: DynamicStorage -> !Dynamic -> [Int]
+ Aztecs.ECS.World.Storage.Dynamic: [insertDyn'] :: DynamicStorage -> !Int -> Dynamic -> Dynamic -> Dynamic
+ Aztecs.ECS.World.Storage.Dynamic: [removeAny'] :: DynamicStorage -> !Int -> Dynamic -> (Maybe DynamicStorage, Dynamic)
+ Aztecs.ECS.World.Storage.Dynamic: [removeDyn'] :: DynamicStorage -> !Int -> Dynamic -> (Maybe Dynamic, Dynamic)
+ Aztecs.ECS.World.Storage.Dynamic: [storageDyn] :: DynamicStorage -> !Dynamic
+ Aztecs.ECS.World.Storage.Dynamic: [storageRnf] :: DynamicStorage -> !Dynamic -> ()
+ Aztecs.ECS.World.Storage.Dynamic: data DynamicStorage
+ Aztecs.ECS.World.Storage.Dynamic: dynStorage :: forall s a. Storage s a => s a -> DynamicStorage
+ Aztecs.ECS.World.Storage.Dynamic: entitiesDyn :: DynamicStorage -> [Int]
+ Aztecs.ECS.World.Storage.Dynamic: insertDyn :: Int -> Dynamic -> DynamicStorage -> DynamicStorage
+ Aztecs.ECS.World.Storage.Dynamic: instance Control.DeepSeq.NFData Aztecs.ECS.World.Storage.Dynamic.DynamicStorage
+ Aztecs.ECS.World.Storage.Dynamic: instance GHC.Show.Show Aztecs.ECS.World.Storage.Dynamic.DynamicStorage
+ Aztecs.ECS.World.Storage.Dynamic: removeAny :: Int -> DynamicStorage -> (Maybe DynamicStorage, DynamicStorage)
+ Aztecs.ECS.World.Storage.Dynamic: removeDyn :: Int -> DynamicStorage -> (Maybe Dynamic, DynamicStorage)
+ Aztecs.Hierarchy: foldWithKey :: (EntityID -> a -> b -> b) -> Hierarchy a -> b -> b
+ Aztecs.Hierarchy: instance Data.Foldable.Foldable Aztecs.Hierarchy.Hierarchy
+ Aztecs.Hierarchy: instance Data.Traversable.Traversable Aztecs.Hierarchy.Hierarchy
+ Aztecs.Hierarchy: instance GHC.Base.Functor Aztecs.Hierarchy.Hierarchy
+ Aztecs.Hierarchy: mapWithAccum :: (EntityID -> a -> b -> (c, b)) -> b -> Hierarchy a -> Hierarchy c
+ Aztecs.Hierarchy: mapWithKey :: (EntityID -> a -> b) -> Hierarchy a -> Hierarchy b
+ Aztecs.Hierarchy: toList :: Hierarchy a -> [(EntityID, a)]
+ Aztecs.Transform: [transformTranslation] :: Transform v r -> !v
+ Aztecs.Transform: instance (Control.DeepSeq.NFData v, Control.DeepSeq.NFData r) => Control.DeepSeq.NFData (Aztecs.Transform.Transform v r)
+ Aztecs.Transform: instance (GHC.Classes.Eq r, GHC.Classes.Eq v) => GHC.Classes.Eq (Aztecs.Transform.Transform v r)
+ Aztecs.Transform: instance (GHC.Num.Num v, GHC.Num.Num r) => GHC.Base.Monoid (Aztecs.Transform.Transform v r)
+ Aztecs.Transform: instance (GHC.Num.Num v, GHC.Num.Num r) => GHC.Base.Semigroup (Aztecs.Transform.Transform v r)
+ Aztecs.Transform: instance (GHC.Show.Show r, GHC.Show.Show v) => GHC.Show.Show (Aztecs.Transform.Transform v r)
+ Aztecs.Transform: instance Aztecs.ECS.Component.Component (Aztecs.Transform.Size (Linear.V2.V2 GHC.Types.Int))
+ Aztecs.Transform: instance Aztecs.ECS.Component.Component (Aztecs.Transform.Transform (Linear.V2.V2 GHC.Types.Int) GHC.Types.Int)
+ Aztecs.Transform: instance Control.DeepSeq.NFData v => Control.DeepSeq.NFData (Aztecs.Transform.Size v)
+ Aztecs.Transform: instance GHC.Generics.Generic (Aztecs.Transform.Size v)
+ Aztecs.Transform: instance GHC.Generics.Generic (Aztecs.Transform.Transform v r)
+ Aztecs.Transform: propagate :: (ArrowQueryReader q, ArrowDynamicQueryReader q, ArrowReaderSystem q arr, Component a, Monoid a) => arr () [Hierarchy a]
+ Aztecs.Transform: propagate2d :: (ArrowQueryReader q, ArrowDynamicQueryReader q, ArrowReaderSystem q arr) => arr () [Hierarchy Transform2D]
+ Aztecs.Transform: size2D :: Size (V2 Integer)
+ Aztecs.Transform: transform2d :: Transform2D
+ Aztecs.Transform: type Size2D = Size (V2 Int)
+ Aztecs.Transform: type Transform2D = Transform (V2 Int) Int
+ Aztecs.Transform: update :: forall q arr b m a. (ArrowQueryReader q, ArrowDynamicQueryReader q, ArrowReaderSystem q arr, ArrowQueueSystem b m arr, Component a, Monoid a) => arr () ()
+ Aztecs.Transform: update2d :: (ArrowQueryReader q, ArrowDynamicQueryReader q, ArrowReaderSystem q arr, ArrowQueueSystem b m arr) => arr () ()
- Aztecs: Transform :: !V2 Int -> !Float -> !V2 Int -> Transform
+ Aztecs: Transform :: !v -> !r -> !v -> Transform v r
- Aztecs: [transformRotation] :: Transform -> !Float
+ Aztecs: [transformRotation] :: Transform v r -> !r
- Aztecs: [transformScale] :: Transform -> !V2 Int
+ Aztecs: [transformScale] :: Transform v r -> !v
- Aztecs: data Transform
+ Aztecs: data Transform v r
- Aztecs: load :: (ArrowSystem Query arr, Asset a) => AssetLoader a o -> arr () o
+ Aztecs: load :: (ArrowQuery q, ArrowSystem q arr, Asset a) => AssetLoader a o -> arr () o
- Aztecs.Asset: load :: (ArrowSystem Query arr, Asset a) => AssetLoader a o -> arr () o
+ Aztecs.Asset: load :: (ArrowQuery q, ArrowSystem q arr, Asset a) => AssetLoader a o -> arr () o
- Aztecs.Asset: loadAssets :: forall a. Typeable a => Schedule IO () ()
+ Aztecs.Asset: loadAssets :: forall a qr rs q s b m arr. (Typeable a, ArrowQueryReader qr, ArrowReaderSystem qr rs, ArrowReaderSchedule rs arr, ArrowQuery q, ArrowSystem q s, ArrowSchedule s arr, MonadIO m, ArrowAccessSchedule b m arr) => arr () ()
- Aztecs.Camera: addCameraTargets :: (ArrowQueryReader qr, ArrowReaderSystem qr arr, ArrowSystem q arr) => arr () ()
+ Aztecs.Camera: addCameraTargets :: (ArrowQueryReader qr, ArrowDynamicQueryReader qr, ArrowReaderSystem qr arr, ArrowQueueSystem b m arr) => arr () ()
- Aztecs.ECS: access :: Monad m => (i -> AccessT m o) -> Schedule m i o
+ Aztecs.ECS: access :: ArrowAccessSchedule b m arr => (i -> m o) -> arr i o
- Aztecs.ECS: bundle :: forall a. (Component a, Typeable (StorageT a)) => a -> Bundle
+ Aztecs.ECS: bundle :: forall c. (MonoidBundle a, Component c) => c -> a
- Aztecs.ECS: reader :: Monad m => ReaderSystem i o -> Schedule m i o
+ Aztecs.ECS: reader :: ArrowReaderSchedule s arr => s i o -> arr i o
- Aztecs.ECS: runSchedule :: Monad m => Schedule m i o -> World -> i -> m (o, World)
+ Aztecs.ECS: runSchedule :: Monad m => Schedule m i o -> World -> i -> m (o, DynamicSchedule m i o, World)
- Aztecs.ECS: system :: Monad m => System i o -> Schedule m i o
+ Aztecs.ECS: system :: ArrowSchedule s arr => s i o -> arr i o
- Aztecs.ECS.Access: class (Monad m) => MonadAccess m
+ Aztecs.ECS.Access: class (MonoidBundle b, Monad m) => MonadAccess b m | m -> b
- Aztecs.ECS.Access: despawn :: MonadAccess m => EntityID -> m ()
+ Aztecs.ECS.Access: despawn :: MonadAccess b m => EntityID -> m ()
- Aztecs.ECS.Access: insert :: (MonadAccess m, Component a, Typeable (StorageT a)) => EntityID -> a -> m ()
+ Aztecs.ECS.Access: insert :: (MonadAccess b m, Component a) => EntityID -> a -> m ()
- Aztecs.ECS.Access: lookup :: (MonadAccess m, Component a) => EntityID -> m (Maybe a)
+ Aztecs.ECS.Access: lookup :: (MonadAccess b m, Component a) => EntityID -> m (Maybe a)
- Aztecs.ECS.Access: remove :: (MonadAccess m, Component a, Typeable (StorageT a)) => EntityID -> m (Maybe a)
+ Aztecs.ECS.Access: remove :: (MonadAccess b m, Component a) => EntityID -> m (Maybe a)
- Aztecs.ECS.Access: spawn :: MonadAccess m => Bundle -> m EntityID
+ Aztecs.ECS.Access: spawn :: MonadAccess b m => b -> m EntityID
- Aztecs.ECS.Access: spawn_ :: MonadAccess m => Bundle -> m ()
+ Aztecs.ECS.Access: spawn_ :: MonadAccess b m => b -> m ()
- Aztecs.ECS.Access.Class: class (Monad m) => MonadAccess m
+ Aztecs.ECS.Access.Class: class (MonoidBundle b, Monad m) => MonadAccess b m | m -> b
- Aztecs.ECS.Access.Class: despawn :: MonadAccess m => EntityID -> m ()
+ Aztecs.ECS.Access.Class: despawn :: MonadAccess b m => EntityID -> m ()
- Aztecs.ECS.Access.Class: insert :: (MonadAccess m, Component a, Typeable (StorageT a)) => EntityID -> a -> m ()
+ Aztecs.ECS.Access.Class: insert :: (MonadAccess b m, Component a) => EntityID -> a -> m ()
- Aztecs.ECS.Access.Class: lookup :: (MonadAccess m, Component a) => EntityID -> m (Maybe a)
+ Aztecs.ECS.Access.Class: lookup :: (MonadAccess b 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: remove :: (MonadAccess b m, Component a) => EntityID -> m (Maybe a)
- Aztecs.ECS.Access.Class: spawn :: MonadAccess m => Bundle -> m EntityID
+ Aztecs.ECS.Access.Class: spawn :: MonadAccess b m => b -> m EntityID
- Aztecs.ECS.Access.Class: spawn_ :: MonadAccess m => Bundle -> m ()
+ Aztecs.ECS.Access.Class: spawn_ :: MonadAccess b m => b -> m ()
- Aztecs.ECS.Query: all :: Query () a -> World -> ([a], World)
+ Aztecs.ECS.Query: all :: Query () a -> Entities -> ([a], Entities)
- Aztecs.ECS.Query: entity :: ArrowQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query: entity :: ArrowDynamicQueryReader arr => arr () EntityID
- Aztecs.ECS.Query.Reader: entity :: ArrowQueryReader arr => arr () EntityID
+ Aztecs.ECS.Query.Reader: entity :: ArrowDynamicQueryReader arr => arr () EntityID
- Aztecs.ECS.Schedule: Schedule :: (Components -> (i -> AccessT m o, Components)) -> Schedule m i o
+ Aztecs.ECS.Schedule: Schedule :: (Components -> (DynamicScheduleT m i o, Components)) -> ScheduleT m i o
- Aztecs.ECS.Schedule: [runSchedule'] :: Schedule m i o -> Components -> (i -> AccessT m o, Components)
+ Aztecs.ECS.Schedule: [runSchedule'] :: ScheduleT m i o -> Components -> (DynamicScheduleT m i o, Components)
- Aztecs.ECS.Schedule: access :: Monad m => (i -> AccessT m o) -> Schedule m i o
+ Aztecs.ECS.Schedule: access :: ArrowAccessSchedule b m arr => (i -> m o) -> arr i o
- Aztecs.ECS.Schedule: reader :: Monad m => ReaderSystem i o -> Schedule m i o
+ Aztecs.ECS.Schedule: reader :: ArrowReaderSchedule s arr => s i o -> arr 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 i o -> World -> i -> m (o, DynamicSchedule m i o, World)
- Aztecs.ECS.Schedule: system :: Monad m => System i o -> Schedule m i o
+ Aztecs.ECS.Schedule: system :: ArrowSchedule s arr => s i o -> arr i o
- Aztecs.ECS.System: queue :: ArrowSystem q arr => (i -> Access ()) -> arr i ()
+ Aztecs.ECS.System: queue :: ArrowQueueSystem b m arr => (i -> m ()) -> arr i ()
- Aztecs.ECS.System.Dynamic: DynamicSystem :: (World -> i -> (o, View, Access ())) -> DynamicSystem i o
+ Aztecs.ECS.System.Dynamic: DynamicSystem :: (Entities -> i -> (o, View, Access (), DynamicSystem i o)) -> DynamicSystem i o
- Aztecs.ECS.System.Dynamic: [runSystemDyn] :: DynamicSystem i o -> World -> i -> (o, View, Access ())
+ Aztecs.ECS.System.Dynamic: [runSystemDyn] :: DynamicSystem i o -> Entities -> i -> (o, View, Access (), DynamicSystem i o)
- Aztecs.ECS.System.Dynamic.Class: class (ArrowDynamicReaderSystem arr) => ArrowDynamicSystem arr
+ Aztecs.ECS.System.Dynamic.Class: class ArrowDynamicSystem q arr | arr -> q
- Aztecs.ECS.System.Dynamic.Class: filterMapDyn :: ArrowDynamicSystem arr => Set ComponentID -> DynamicQuery i o -> (Node -> Bool) -> arr i [o]
+ Aztecs.ECS.System.Dynamic.Class: filterMapDyn :: ArrowDynamicSystem q arr => Set ComponentID -> q i o -> (Node -> Bool) -> arr i [o]
- Aztecs.ECS.System.Dynamic.Class: mapDyn :: ArrowDynamicSystem arr => Set ComponentID -> DynamicQuery i o -> arr i [o]
+ Aztecs.ECS.System.Dynamic.Class: mapDyn :: ArrowDynamicSystem q arr => Set ComponentID -> q i o -> arr i [o]
- Aztecs.ECS.System.Dynamic.Class: mapSingleDyn :: ArrowDynamicSystem arr => Set ComponentID -> DynamicQuery i o -> arr i o
+ Aztecs.ECS.System.Dynamic.Class: mapSingleDyn :: ArrowDynamicSystem q arr => Set ComponentID -> q i o -> arr 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 :: ArrowDynamicSystem q arr => Set ComponentID -> q i o -> arr i (Maybe o)
- Aztecs.ECS.System.Dynamic.Reader: DynamicReaderSystem :: (World -> i -> o) -> DynamicReaderSystem i o
+ Aztecs.ECS.System.Dynamic.Reader: DynamicReaderSystem :: (Entities -> i -> (o, Access (), DynamicReaderSystem i o)) -> DynamicReaderSystem i o
- Aztecs.ECS.System.Dynamic.Reader: [runReaderSystemDyn] :: DynamicReaderSystem i o -> World -> i -> o
+ Aztecs.ECS.System.Dynamic.Reader: [runReaderSystemDyn] :: DynamicReaderSystem i o -> Entities -> i -> (o, Access (), DynamicReaderSystem i o)
- Aztecs.ECS.System.Dynamic.Reader: allDyn :: ArrowDynamicReaderSystem arr => Set ComponentID -> DynamicQueryReader i o -> arr i [o]
+ Aztecs.ECS.System.Dynamic.Reader: allDyn :: ArrowDynamicReaderSystem q arr => Set ComponentID -> q i o -> arr i [o]
- Aztecs.ECS.System.Dynamic.Reader: class (Arrow arr) => ArrowDynamicReaderSystem arr
+ Aztecs.ECS.System.Dynamic.Reader: class (Arrow arr) => ArrowDynamicReaderSystem q arr | arr -> q
- Aztecs.ECS.System.Dynamic.Reader: filterDyn :: ArrowDynamicReaderSystem arr => Set ComponentID -> DynamicQueryReader i o -> (Node -> Bool) -> arr i [o]
+ Aztecs.ECS.System.Dynamic.Reader: filterDyn :: ArrowDynamicReaderSystem q arr => Set ComponentID -> q i o -> (Node -> Bool) -> arr i [o]
- Aztecs.ECS.System.Dynamic.Reader: singleDyn :: ArrowDynamicReaderSystem arr => Set ComponentID -> DynamicQueryReader () a -> arr () a
+ Aztecs.ECS.System.Dynamic.Reader: singleDyn :: ArrowDynamicReaderSystem q arr => Set ComponentID -> q () 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: allDyn :: ArrowDynamicReaderSystem q arr => Set ComponentID -> q i o -> arr i [o]
- Aztecs.ECS.System.Dynamic.Reader.Class: class (Arrow arr) => ArrowDynamicReaderSystem arr
+ Aztecs.ECS.System.Dynamic.Reader.Class: class (Arrow arr) => ArrowDynamicReaderSystem q arr | arr -> q
- 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: filterDyn :: ArrowDynamicReaderSystem q arr => Set ComponentID -> q 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.Dynamic.Reader.Class: singleDyn :: ArrowDynamicReaderSystem q arr => Set ComponentID -> q () a -> arr () a
- Aztecs.ECS.System.Reader: queue :: ArrowSystem q arr => (i -> Access ()) -> arr i ()
+ Aztecs.ECS.System.Reader: queue :: ArrowQueueSystem b m arr => (i -> m ()) -> arr i ()
- Aztecs.ECS.View: unview :: View -> World -> World
+ Aztecs.ECS.View: unview :: View -> Entities -> Entities
- Aztecs.ECS.World: World :: !Archetypes -> !Components -> !Map EntityID ArchetypeID -> !EntityID -> World
+ Aztecs.ECS.World: World :: Entities -> !EntityID -> World
- Aztecs.ECS.World: [entities] :: World -> !Map EntityID ArchetypeID
+ Aztecs.ECS.World: [entities] :: World -> Entities
- Aztecs.ECS.World: insert :: forall a. (Component a, Typeable (StorageT a)) => EntityID -> a -> World -> World
+ Aztecs.ECS.World: insert :: forall a. Component a => EntityID -> a -> World -> World
- Aztecs.ECS.World: insertWithId :: (Component a, Typeable (StorageT a)) => EntityID -> ComponentID -> a -> World -> World
+ Aztecs.ECS.World: insertWithId :: Component a => EntityID -> ComponentID -> a -> World -> World
- Aztecs.ECS.World: remove :: forall a. (Component a, Typeable (StorageT a)) => EntityID -> World -> (Maybe a, World)
+ Aztecs.ECS.World: remove :: forall a. Component 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: removeWithId :: forall a. Component a => EntityID -> ComponentID -> World -> (Maybe a, World)
- Aztecs.ECS.World: spawnWithArchetypeId :: forall a. (Component a, Typeable (StorageT a)) => a -> ComponentID -> ArchetypeID -> World -> (EntityID, World)
+ Aztecs.ECS.World: spawnWithArchetypeId :: forall a. Component a => ArchetypeID -> ComponentID -> a -> World -> (EntityID, World)
- Aztecs.ECS.World.Archetype: Archetype :: Map ComponentID AnyStorage -> Archetype
+ Aztecs.ECS.World.Archetype: Archetype :: Map ComponentID DynamicStorage -> Archetype
- Aztecs.ECS.World.Archetype: [storages] :: Archetype -> Map ComponentID AnyStorage
+ Aztecs.ECS.World.Archetype: [storages] :: Archetype -> Map ComponentID DynamicStorage
- Aztecs.ECS.World.Archetype: removeStorages :: EntityID -> Archetype -> (Map ComponentID AnyStorage, Archetype)
+ Aztecs.ECS.World.Archetype: removeStorages :: EntityID -> Archetype -> (Map ComponentID DynamicStorage, Archetype)
- Aztecs.ECS.World.Archetypes: insert :: (Component a, Typeable (StorageT a)) => EntityID -> ArchetypeID -> ComponentID -> a -> Archetypes -> (Maybe ArchetypeID, Archetypes)
+ Aztecs.ECS.World.Archetypes: insert :: Component a => EntityID -> ArchetypeID -> ComponentID -> a -> Archetypes -> (Maybe ArchetypeID, Archetypes)
- Aztecs.ECS.World.Archetypes: lookup :: Set ComponentID -> Archetypes -> Map ArchetypeID Node
+ Aztecs.ECS.World.Archetypes: lookup :: ArchetypeID -> Archetypes -> Maybe Node
- Aztecs.ECS.World.Archetypes: remove :: (Component a, Typeable (StorageT a)) => EntityID -> ArchetypeID -> ComponentID -> Archetypes -> (Maybe (a, ArchetypeID), Archetypes)
+ Aztecs.ECS.World.Archetypes: remove :: Component a => EntityID -> ArchetypeID -> ComponentID -> Archetypes -> (Maybe (a, ArchetypeID), Archetypes)
- Aztecs.Hierarchy: hierarchies :: (ArrowQueryReader q, ArrowReaderSystem q arr) => q i a -> arr i [[Hierarchy a]]
+ Aztecs.Hierarchy: hierarchies :: (ArrowQueryReader q, ArrowDynamicQueryReader 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: hierarchy :: (ArrowQueryReader q, ArrowDynamicQueryReader q, ArrowReaderSystem q arr) => EntityID -> q i a -> arr i (Maybe (Hierarchy a))
- Aztecs.Hierarchy: update :: (ArrowQueryReader qr, ArrowQuery q, ArrowReaderSystem qr arr, ArrowSystem q arr) => arr () ()
+ Aztecs.Hierarchy: update :: (ArrowQueryReader qr, ArrowDynamicQueryReader qr, ArrowReaderSystem qr arr, ArrowQueueSystem b m arr) => arr () ()
- Aztecs.Transform: Size :: V2 Int -> Size
+ Aztecs.Transform: Size :: v -> Size v
- Aztecs.Transform: Transform :: !V2 Int -> !Float -> !V2 Int -> Transform
+ Aztecs.Transform: Transform :: !v -> !r -> !v -> Transform v r
- Aztecs.Transform: [transformRotation] :: Transform -> !Float
+ Aztecs.Transform: [transformRotation] :: Transform v r -> !r
- Aztecs.Transform: [transformScale] :: Transform -> !V2 Int
+ Aztecs.Transform: [transformScale] :: Transform v r -> !v
- Aztecs.Transform: [unSize] :: Size -> V2 Int
+ Aztecs.Transform: [unSize] :: Size v -> v
- Aztecs.Transform: data Transform
+ Aztecs.Transform: data Transform v r
- Aztecs.Transform: newtype Size
+ Aztecs.Transform: newtype Size v
Files
- aztecs.cabal +35/−11
- src/Aztecs.hs +7/−3
- src/Aztecs/Asset.hs +6/−136
- src/Aztecs/Asset/AssetLoader.hs +59/−0
- src/Aztecs/Asset/AssetLoader/Class.hs +19/−0
- src/Aztecs/Asset/AssetServer.hs +114/−0
- src/Aztecs/Asset/Class.hs +10/−0
- src/Aztecs/Camera.hs +7/−3
- src/Aztecs/ECS.hs +32/−7
- src/Aztecs/ECS/Access.hs +6/−2
- src/Aztecs/ECS/Access/Class.hs +7/−7
- src/Aztecs/ECS/Query.hs +27/−26
- src/Aztecs/ECS/Query/Class.hs +1/−0
- src/Aztecs/ECS/Query/Dynamic.hs +32/−38
- src/Aztecs/ECS/Query/Dynamic/Reader.hs +18/−11
- src/Aztecs/ECS/Query/Dynamic/Reader/Class.hs +2/−2
- src/Aztecs/ECS/Query/Reader.hs +21/−37
- src/Aztecs/ECS/Query/Reader/Class.hs +1/−4
- src/Aztecs/ECS/Schedule.hs +73/−48
- src/Aztecs/ECS/Schedule/Access.hs +27/−0
- src/Aztecs/ECS/Schedule/Access/Class.hs +11/−0
- src/Aztecs/ECS/Schedule/Class.hs +10/−0
- src/Aztecs/ECS/Schedule/Dynamic.hs +44/−0
- src/Aztecs/ECS/Schedule/Dynamic/Reader.hs +45/−0
- src/Aztecs/ECS/Schedule/Reader.hs +56/−0
- src/Aztecs/ECS/Schedule/Reader/Class.hs +10/−0
- src/Aztecs/ECS/System.hs +30/−15
- src/Aztecs/ECS/System/Class.hs +0/−4
- src/Aztecs/ECS/System/Dynamic.hs +72/−22
- src/Aztecs/ECS/System/Dynamic/Class.hs +7/−66
- src/Aztecs/ECS/System/Dynamic/Reader.hs +41/−31
- src/Aztecs/ECS/System/Dynamic/Reader/Class.hs +6/−5
- src/Aztecs/ECS/System/Queue.hs +31/−0
- src/Aztecs/ECS/System/Queue/Class.hs +10/−0
- src/Aztecs/ECS/System/Reader.hs +20/−24
- src/Aztecs/ECS/View.hs +10/−10
- src/Aztecs/ECS/World.hs +29/−175
- src/Aztecs/ECS/World/Archetype.hs +16/−132
- src/Aztecs/ECS/World/Archetypes.hs +42/−95
- src/Aztecs/ECS/World/Bundle.hs +52/−0
- src/Aztecs/ECS/World/Bundle/Class.hs +11/−0
- src/Aztecs/ECS/World/Bundle/Dynamic.hs +21/−0
- src/Aztecs/ECS/World/Bundle/Dynamic/Class.hs +9/−0
- src/Aztecs/ECS/World/Entities.hs +215/−0
- src/Aztecs/ECS/World/Storage.hs +3/−3
- src/Aztecs/ECS/World/Storage/Dynamic.hs +73/−0
- src/Aztecs/Hierarchy.hs +45/−16
- src/Aztecs/Time.hs +2/−4
- src/Aztecs/Transform.hs +87/−10
- test/Main.hs +45/−6
aztecs.cabal view
@@ -1,23 +1,27 @@ cabal-version: 2.4 name: aztecs-version: 0.6.0+version: 0.7.0 license: BSD-3-Clause license-file: LICENSE maintainer: matt@hunzinger.me author: Matt Hunzinger-synopsis: A type-safe and friendly Entity-Component-System (ECS) for Haskell-description: The Entity-Component-System (ECS) pattern is commonly used in video game develop to represent world objects.- .- ECS follows the principal of composition over inheritence. Each type of- object (e.g. sword, monster, etc), in the game has a unique EntityId. Each- entity has various Components associated with it (material, weight, damage, etc).- Systems act on entities which have the required Components.-homepage: https://github.com/matthunz/aztecs+homepage: https://github.com/aztecs-hs/aztecs+synopsis:+ A modular game engine and Entity-Component-System (ECS) for Haskell.++description:+ A modular game engine and Entity-Component-System (ECS) for Haskell.+ An ECS is a modern approach to organizing your application state as a database,+ providing patterns for data-oriented design and parallel processing.+ Aztecs provides side-effect free components and systems,+ as well as backends for rendering and input (such as `aztecs-sdl`),+ allowing you to structure your game as simple function of `Input -> World -> World`.+ category: Game Engine source-repository head type: git- location: https://github.com/matthunz/aztecs.git+ location: https://github.com/aztecs-hs/aztecs.git library exposed-modules:@@ -36,27 +40,47 @@ Aztecs.ECS.Query.Reader Aztecs.ECS.Query.Reader.Class Aztecs.ECS.Schedule+ Aztecs.ECS.Schedule.Access+ Aztecs.ECS.Schedule.Access.Class+ Aztecs.ECS.Schedule.Class+ Aztecs.ECS.Schedule.Dynamic+ Aztecs.ECS.Schedule.Dynamic.Reader+ Aztecs.ECS.Schedule.Reader+ Aztecs.ECS.Schedule.Reader.Class 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.Queue+ Aztecs.ECS.System.Queue.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.Bundle+ Aztecs.ECS.World.Bundle.Class+ Aztecs.ECS.World.Bundle.Dynamic+ Aztecs.ECS.World.Bundle.Dynamic.Class Aztecs.ECS.World.Components+ Aztecs.ECS.World.Entities Aztecs.ECS.World.Storage+ Aztecs.ECS.World.Storage.Dynamic Aztecs.Asset+ Aztecs.Asset.AssetLoader+ Aztecs.Asset.AssetLoader.Class+ Aztecs.Asset.AssetServer+ Aztecs.Asset.Class Aztecs.Camera Aztecs.Hierarchy Aztecs.Input Aztecs.Time Aztecs.Transform Aztecs.Window+ hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall@@ -66,7 +90,7 @@ deepseq >=1, linear >=1, mtl >=2,- parallel >=3,+ parallel >=3 test-suite aztecs-test type: exitcode-stdio-1.0
src/Aztecs.hs view
@@ -55,8 +55,6 @@ load, Camera (..), CameraTarget (..),- Transform (..),- transform, Key (..), KeyboardInput (..), isKeyPressed,@@ -64,6 +62,12 @@ wasKeyReleased, MouseInput (..), Time (..),+ Transform (..),+ Transform2D,+ transform2d,+ Size (..),+ Size2D,+ size2D, Window (..), ) where@@ -80,5 +84,5 @@ wasKeyReleased, ) import Aztecs.Time-import Aztecs.Transform (Transform (..), transform)+import Aztecs.Transform import Aztecs.Window
src/Aztecs/Asset.hs view
@@ -1,154 +1,24 @@ {-# 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,+ MonadAssetLoader (..), Asset (..), Handle (..),- MonadAssetLoader (..),- AssetLoader,- AssetLoaderT (..),- load,+ lookupAsset, setup,- loadQuery, loadAssets,- lookupAsset,+ load, ) 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+import Aztecs.Asset.AssetLoader+import Aztecs.Asset.AssetServer+import Aztecs.Asset.Class
+ src/Aztecs/Asset/AssetLoader.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE Arrows #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Aztecs.Asset.AssetLoader+ ( MonadAssetLoader (..),+ AssetLoader,+ AssetLoaderT (..),+ load,+ loadQuery,+ )+where++import Aztecs.Asset.AssetLoader.Class+import Aztecs.Asset.AssetServer (AssetId (..), AssetServer (..), Handle (..))+import Aztecs.Asset.Class+import Aztecs.ECS+import qualified Aztecs.ECS.Query as Q+import qualified Aztecs.ECS.System as S+import Control.Arrow (returnA)+import Control.Concurrent (forkIO)+import Control.Monad.Identity (Identity)+import Control.Monad.State.Strict (MonadState (..), StateT, runState)+import Data.IORef (newIORef, writeIORef)+import qualified Data.Map.Strict as Map++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 :: (ArrowQuery q, ArrowSystem q arr, Asset a) => AssetLoader a o -> arr () o+load a = S.mapSingle $ loadQuery a
+ src/Aztecs/Asset/AssetLoader/Class.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.Asset.AssetLoader.Class+ ( MonadAssetLoader (..),+ )+where++import Aztecs.Asset.AssetServer (Handle)+import Aztecs.Asset.Class++class MonadAssetLoader a m | m -> a where+ asset :: FilePath -> AssetConfig a -> m (Handle a)
+ src/Aztecs/Asset/AssetServer.hs view
@@ -0,0 +1,114 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE Arrows #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.Asset.AssetServer+ ( AssetId (..),+ AssetServer (..),+ assetServer,+ Handle (..),+ setup,+ loadAssets,+ lookupAsset,+ )+where++import Aztecs.ECS+import qualified Aztecs.ECS.Access as A+import qualified Aztecs.ECS.Query as Q+import qualified Aztecs.ECS.System as S+import Control.Arrow (returnA)+import Control.DeepSeq+import Control.Monad.IO.Class (MonadIO (..))+import Data.Data (Typeable)+import Data.Foldable (foldrM)+import Data.IORef (IORef, readIORef)+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++assetServer :: AssetServer a+assetServer =+ AssetServer+ { assetServerAssets = Map.empty,+ loadingAssets = Map.empty,+ nextAssetId = AssetId 0+ }++newtype Handle a = Handle {handleId :: AssetId}+ deriving (Eq, Ord, Show)++instance NFData (Handle a) where+ rnf = rwhnf++lookupAsset :: Handle a -> AssetServer a -> Maybe a+lookupAsset h server = Map.lookup (handleId h) (assetServerAssets server)++loadAssets ::+ forall a qr rs q s b m arr.+ ( Typeable a,+ ArrowQueryReader qr,+ ArrowReaderSystem qr rs,+ ArrowReaderSchedule rs arr,+ ArrowQuery q,+ ArrowSystem q s,+ ArrowSchedule s arr,+ MonadIO m,+ ArrowAccessSchedule b m arr+ ) =>+ arr () ()+loadAssets = proc () -> do+ server <- reader $ S.single (Q.fetch @_ @(AssetServer a)) -< ()+ server' <-+ access+ ( \server ->+ liftIO $+ 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 $ assetServer @a
+ src/Aztecs/Asset/Class.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE TypeFamilies #-}++module Aztecs.Asset.Class (Asset (..)) where++import Data.Data (Typeable)++class (Typeable a) => Asset a where+ type AssetConfig a++ loadAsset :: FilePath -> AssetConfig a -> IO a
src/Aztecs/Camera.hs view
@@ -12,9 +12,7 @@ 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 (..))@@ -43,7 +41,13 @@ instance Component CameraTarget -- | Add `CameraTarget` components to entities with a new `Draw` component.-addCameraTargets :: (ArrowQueryReader qr, ArrowReaderSystem qr arr, ArrowSystem q arr) => arr () ()+addCameraTargets ::+ ( ArrowQueryReader qr,+ ArrowDynamicQueryReader qr,+ ArrowReaderSystem qr arr,+ ArrowQueueSystem b m arr+ ) =>+ arr () () addCameraTargets = proc () -> do windows <- S.all (Q.entity &&& Q.fetch @_ @Window) -< () newCameras <- S.filter (Q.entity &&& Q.fetch @_ @Camera) (without @CameraTarget) -< ()
src/Aztecs/ECS.hs view
@@ -53,21 +53,33 @@ ( Access, runAccessT, Bundle,- bundle,+ MonoidBundle (..),+ DynamicBundle,+ MonoidDynamicBundle (..), Component (..), EntityID, Query,+ ArrowQueryReader,+ ArrowQuery,+ ArrowDynamicQueryReader,+ ArrowDynamicQuery, QueryFilter, with, without, System,+ ArrowReaderSystem,+ ArrowSystem,+ ArrowQueueSystem, Schedule,+ ArrowReaderSchedule,+ ArrowSchedule,+ ArrowAccessSchedule, reader, system,+ delay, forever, forever_, access,- task, runSchedule, runSchedule_, World,@@ -77,18 +89,31 @@ 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.Query+ ( ArrowDynamicQuery,+ ArrowDynamicQueryReader,+ ArrowQuery,+ ArrowQueryReader,+ Query,+ QueryFilter,+ with,+ without,+ ) import Aztecs.ECS.Schedule- ( Schedule,+ ( ArrowAccessSchedule,+ ArrowReaderSchedule,+ ArrowSchedule,+ Schedule, access,+ delay, forever, forever_, reader, runSchedule, runSchedule_, system,- task, )-import Aztecs.ECS.System (System)+import Aztecs.ECS.System (ArrowQueueSystem, ArrowReaderSystem, ArrowSystem, System) import Aztecs.ECS.World (World)-import Aztecs.ECS.World.Archetype (Bundle, bundle)+import Aztecs.ECS.World.Bundle (Bundle, MonoidBundle (..))+import Aztecs.ECS.World.Bundle.Dynamic (DynamicBundle, MonoidDynamicBundle (..))
src/Aztecs/ECS/Access.hs view
@@ -1,5 +1,7 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-} module Aztecs.ECS.Access ( Access,@@ -12,6 +14,8 @@ import Aztecs.ECS.Access.Class (MonadAccess (..)) import Aztecs.ECS.World (World (..)) import qualified Aztecs.ECS.World as W+import Aztecs.ECS.World.Bundle (Bundle)+import Control.Monad.Fix (MonadFix) import Control.Monad.IO.Class (MonadIO) import Control.Monad.Identity (Identity) import Control.Monad.State.Strict (MonadState (..), StateT (..))@@ -21,13 +25,13 @@ -- | Access into the `World`. newtype AccessT m a = AccessT {unAccessT :: StateT World m a}- deriving (Functor, Applicative, Monad, MonadIO)+ deriving (Functor, Applicative, Monad, MonadFix, 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+instance (Monad m) => MonadAccess Bundle (AccessT m) where spawn b = AccessT $ do !w <- get let !(e, w') = W.spawn b w
src/Aztecs/ECS/Access/Class.hs view
@@ -1,32 +1,32 @@ {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FunctionalDependencies #-} 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 Aztecs.ECS.World.Bundle (MonoidBundle (..)) import Prelude hiding (all, lookup, map) -- | Monadic access to a `World`.-class (Monad m) => MonadAccess m where+class (MonoidBundle b, Monad m) => MonadAccess b m | m -> b where -- | Spawn an entity with a component.- spawn :: Bundle -> m EntityID+ spawn :: b -> m EntityID -- | Spawn an entity with a component.- spawn_ :: Bundle -> m ()+ spawn_ :: b -> m () spawn_ c = do _ <- spawn c return () -- | Insert a component into an entity.- insert :: (Component a, Typeable (StorageT a)) => EntityID -> a -> m ()+ insert :: (Component 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)+ remove :: (Component a) => EntityID -> m (Maybe a) -- | Despawn an entity. despawn :: EntityID -> m ()
src/Aztecs/ECS/Query.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-}@@ -28,18 +29,18 @@ import Aztecs.ECS.Component import Aztecs.ECS.Query.Class (ArrowQuery (..))-import Aztecs.ECS.Query.Dynamic (DynamicQuery (..))+import Aztecs.ECS.Query.Dynamic (DynamicQuery (..), fromDynReader) 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 (QueryFilter (..), QueryReader (..), 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 Aztecs.ECS.World.Entities (Entities (..))+import Control.Arrow (Arrow (..), ArrowChoice (..)) import Control.Category (Category (..)) import Data.Set (Set) import qualified Data.Set as Set@@ -48,24 +49,21 @@ -- | Query for matching entities. -- -- === Do notation:--- > move :: (Monad m) => Query m () Position+-- > move :: (ArrowQuery arr) => arr () 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 :: (ArrowQuery arr) => arr () 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 :: (ArrowQuery arr) => arr () 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)+newtype Query i o = Query {runQuery :: Components -> (ReadsWrites, Components, DynamicQuery i o)}+ deriving (Functor) instance Applicative (Query i) where pure a = Query (mempty,,pure a)@@ -85,21 +83,17 @@ arr f = Query (mempty,,arr f) first (Query f) = Query $ \comps -> let (cIds, comps', qS) = f comps in (cIds, comps', first qS) +instance ArrowChoice Query where+ left (Query f) = Query $ \comps -> let (cIds, comps', qS) = f comps in (cIds, comps', left 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)+ fetch = fromReader fetch+ fetchMaybe = fromReader fetchMaybe 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)+ entity = fromReader entity+ fetchDyn = fromReader . fetchDyn+ fetchMaybeDyn = fromReader . fetchMaybeDyn instance ArrowDynamicQuery Query where setDyn cId = Query (ReadsWrites Set.empty (Set.singleton cId),,setDyn cId)@@ -110,6 +104,11 @@ let (cId, cs') = CS.insert @a cs in (ReadsWrites Set.empty (Set.singleton cId), cs', setDyn cId) +fromReader :: QueryReader i o -> Query i o+fromReader (QueryReader f) = Query $ \cs ->+ let (cIds, cs', dynQ) = f cs in (ReadsWrites cIds Set.empty, cs', fromDynReader dynQ)++-- | Reads and writes of a `Query`. data ReadsWrites = ReadsWrites { reads :: !(Set ComponentID), writes :: !(Set ComponentID)@@ -122,17 +121,19 @@ instance Monoid ReadsWrites where mempty = ReadsWrites mempty mempty +-- | `True` if the reads and writes of two `Query`s overlap. 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)+-- | Match all entities.+all :: Query () a -> Entities -> ([a], Entities) 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))+ (AS.find (reads rws <> writes rws) (archetypes w)) in (concat as, w {components = cs'})
src/Aztecs/ECS/Query/Class.hs view
@@ -3,6 +3,7 @@ import Aztecs.ECS.Component import Aztecs.ECS.Query.Reader.Class (ArrowQueryReader) +-- | Arrow for queries that can update entities. 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
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE TypeFamilies #-} module Aztecs.ECS.Query.Dynamic@@ -6,6 +7,7 @@ DynamicQuery (..), ArrowDynamicQueryReader (..), ArrowDynamicQuery (..),+ fromDynReader, -- * Dynamic query filters DynamicQueryFilter (..),@@ -14,64 +16,56 @@ 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 (DynamicQueryFilter (..), DynamicQueryReader (..)) 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.Arrow (Arrow (..), ArrowChoice (..)) import Control.Category (Category (..))-import Prelude hiding (all, any, id, lookup, map, mapM, reads, (.))+import Data.Either (partitionEithers)+import Prelude hiding ((.)) -- | 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')+ deriving (Functor) 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'')- }+ f <*> g = DynamicQuery $ \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'- }+ f . g = DynamicQuery $ \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)+ first f = DynamicQuery $ \bds es arch ->+ let (bs, ds) = unzip bds+ (cs, arch') = dynQueryAll f bs es arch+ in (zip cs ds, arch') - fetchDyn cId =- DynamicQuery $ \_ _ arch -> let !as = A.all cId arch in (fmap snd as, arch)+instance ArrowChoice DynamicQuery where+ left f = DynamicQuery $ \eds es arch ->+ let (es', ds) = partitionEithers eds+ (cs, arch') = dynQueryAll f es' es arch+ in (fmap Left cs ++ fmap Right ds, arch') - fetchMaybeDyn cId =- DynamicQuery $ \_ _ arch -> let as = A.allMaybe cId arch in (fmap snd as, arch)+instance ArrowDynamicQueryReader DynamicQuery where+ entity = fromDynReader entity+ fetchDyn = fromDynReader . fetchDyn+ fetchMaybeDyn = fromDynReader . fetchMaybeDyn instance ArrowDynamicQuery DynamicQuery where- setDyn cId =- DynamicQuery $ \is _ arch -> let !arch' = A.withAscList cId is arch in (is, arch')+ setDyn cId = DynamicQuery $ \is es arch ->+ let !arch' = A.insertAscList cId (zip es is) arch in (is, arch')++fromDynReader :: DynamicQueryReader i o -> DynamicQuery i o+fromDynReader q = DynamicQuery $ \is es arch ->+ let os = dynQueryReaderAll q is es arch in (os, arch)
src/Aztecs/ECS/Query/Dynamic/Reader.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE TypeFamilies #-} module Aztecs.ECS.Query.Dynamic.Reader@@ -16,17 +17,16 @@ 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 qualified Aztecs.ECS.World.Storage as S+import Control.Arrow+import Control.Category+import Data.Either (partitionEithers) 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+ deriving (Functor) instance Applicative (DynamicQueryReader i) where pure a = DynamicQueryReader $ \_ es _ -> replicate (length es) a@@ -49,12 +49,19 @@ cs = dynQueryReaderAll f bs es arch in zip cs ds +instance ArrowChoice DynamicQueryReader where+ left f = DynamicQueryReader $ \eds es arch ->+ let (es', ds) = partitionEithers eds+ cs = dynQueryReaderAll f es' es arch+ in fmap Left cs ++ fmap Right 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+ entity = DynamicQueryReader $ \_ es _ -> es+ fetchDyn cId = DynamicQueryReader $ \_ _ arch ->+ let !as = maybe [] S.toList (A.lookupStorage cId arch) in fmap snd as+ fetchMaybeDyn cId = DynamicQueryReader $ \_ es arch -> case A.lookupStorage cId arch of+ Just s -> let !as = S.toList s in fmap Just $ snd <$> as+ Nothing -> map (const Nothing) es data DynamicQueryFilter = DynamicQueryFilter { filterWith :: !(Set ComponentID),
src/Aztecs/ECS/Query/Dynamic/Reader/Class.hs view
@@ -5,8 +5,8 @@ import Control.Arrow (Arrow (..), (>>>)) class (Arrow arr) => ArrowDynamicQueryReader arr where- -- | Fetch the `EntityID` belonging to this entity.- entityDyn :: arr () EntityID+ -- | Fetch the currently matched `EntityID`.+ entity :: arr () EntityID -- | Fetch a `Component` by its `ComponentID`. fetchDyn :: (Component a) => ComponentID -> arr () a
src/Aztecs/ECS/Query/Reader.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-}@@ -26,67 +27,50 @@ 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.Arrow (Arrow (..), ArrowChoice (..)) 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+-- | Query to read from entities. 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)+ = QueryReader {runQueryReader :: Components -> (Set ComponentID, Components, DynamicQueryReader i o)}+ deriving (Functor) instance Applicative (QueryReader i) where- pure a = Query $ \cs -> (mempty, cs, pure a)- (Query f) <*> (Query g) = Query $ \cs ->+ pure a = QueryReader $ \cs -> (mempty, cs, pure a)+ (QueryReader f) <*> (QueryReader g) = QueryReader $ \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 ->+ id = QueryReader $ \cs -> (mempty, cs, id)+ (QueryReader f) . (QueryReader g) = QueryReader $ \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)+ arr f = QueryReader $ \cs -> (mempty, cs, arr f)+ first (QueryReader f) = QueryReader $ \comps -> let (cIds, comps', qS) = f comps in (cIds, comps', first qS) +instance ArrowChoice QueryReader where+ left (QueryReader f) = QueryReader $ \comps -> let (cIds, comps', qS) = f comps in (cIds, comps', left 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)+ fetch = QueryReader $ \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)+ fetchMaybe = QueryReader $ \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)+ entity = QueryReader $ \cs -> (mempty, cs, entity)+ fetchDyn cId = QueryReader $ \cs -> (Set.singleton cId, cs, fetchDyn cId)+ fetchMaybeDyn cId = QueryReader $ \cs -> (Set.singleton cId, cs, fetchMaybeDyn cId) -- | Filter for a `Query`. newtype QueryFilter = QueryFilter {runQueryFilter :: Components -> (DynamicQueryFilter, Components)}
src/Aztecs/ECS/Query/Reader/Class.hs view
@@ -1,13 +1,10 @@ module Aztecs.ECS.Query.Reader.Class (ArrowQueryReader (..)) where import Aztecs.ECS.Component-import Aztecs.ECS.Entity (EntityID) import Control.Arrow (Arrow (..), (>>>)) +-- | Arrow for queries that can read from entities. 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
src/Aztecs/ECS/Schedule.hs view
@@ -1,21 +1,27 @@ {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-} module Aztecs.ECS.Schedule ( -- * Schedules- Schedule (..),- reader,- system,+ Schedule,+ ScheduleT (..),+ ArrowReaderSchedule (..),+ ArrowSchedule (..),+ ArrowAccessSchedule (..),+ delay, forever, forever_,- access,- task, runSchedule, runSchedule_, ) where import Aztecs.ECS.Access (AccessT (..), runAccessT)+import Aztecs.ECS.Schedule.Access.Class (ArrowAccessSchedule (..))+import Aztecs.ECS.Schedule.Class (ArrowSchedule (..))+import Aztecs.ECS.Schedule.Dynamic (DynamicSchedule, DynamicScheduleT (..))+import Aztecs.ECS.Schedule.Reader.Class (ArrowReaderSchedule (..)) import Aztecs.ECS.System (System (..)) import Aztecs.ECS.System.Dynamic (DynamicSystem (..)) import Aztecs.ECS.System.Dynamic.Reader (DynamicReaderSystem (..))@@ -23,78 +29,97 @@ import qualified Aztecs.ECS.View as V import Aztecs.ECS.World (World (..)) import qualified Aztecs.ECS.World as W+import Aztecs.ECS.World.Bundle (Bundle) import Aztecs.ECS.World.Components (Components)-import Control.Arrow (Arrow (..))+import Aztecs.ECS.World.Entities (Entities (..))+import Control.Arrow (Arrow (..), ArrowLoop (..)) import Control.Category (Category (..)) import Control.DeepSeq import Control.Exception (evaluate)-import Control.Monad ((>=>))+import Control.Monad.Fix import Control.Monad.Identity (Identity (runIdentity)) import Control.Monad.State (MonadState (..)) import Control.Monad.Trans (MonadTrans (..)) import Data.Functor (void)+import Prelude hiding (id, (.)) -newtype Schedule m i o = Schedule {runSchedule' :: Components -> (i -> AccessT m o, Components)}+type Schedule m = ScheduleT (AccessT m)++accessDyn :: (Monad m) => (i -> m o) -> DynamicScheduleT m i o+accessDyn f = DynamicSchedule $ \i -> do+ a <- f i+ return (a, accessDyn f)++delayDyn :: (Applicative m) => a -> DynamicScheduleT m a a+delayDyn d = DynamicSchedule $ \this -> pure (d, delayDyn this)++-- | System schedule.+newtype ScheduleT m i o = Schedule {runSchedule' :: Components -> (DynamicScheduleT m i o, Components)} deriving (Functor) -instance (Monad m) => Category (Schedule m) where- id = Schedule $ \cs -> (return, cs)+instance (Monad m) => Category (ScheduleT m) where+ id = Schedule $ \cs -> (id, cs) Schedule f . Schedule g = Schedule $ \cs -> let (g', cs') = g cs (f', cs'') = f cs'- in (g' >=> f', cs'')+ in (f' . g', 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')+instance (Monad m) => Arrow (ScheduleT m) where+ arr f = Schedule $ \cs -> (arr f, cs)+ first (Schedule f) = Schedule $ \cs -> let (f', cs') = f cs in (first f', 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')+instance (MonadFix m) => ArrowLoop (ScheduleT m) where+ loop (Schedule f) = Schedule $ \cs -> let (f', cs') = f cs in (loop f', cs') -runSchedule_ :: (Monad m) => Schedule m () () -> m ()-runSchedule_ s = void (runSchedule s W.empty ())+instance (Monad m) => ArrowAccessSchedule Bundle (AccessT m) (Schedule m) where+ access f = Schedule $ \cs -> (accessDyn f, cs) -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')+instance (Monad m) => ArrowReaderSchedule ReaderSystem (Schedule m) where+ reader s = Schedule $ \cs ->+ let (dynS, _, cs') = runReaderSystem s cs+ go dynSAcc i = AccessT $ do+ w <- get+ let (o, a, dynSAcc') = runReaderSystemDyn dynSAcc (W.entities w) i+ ((), w') = runIdentity $ runAccessT a w+ put w'+ return (o, DynamicSchedule $ go dynSAcc')+ in (DynamicSchedule $ go dynS, 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')+instance (Monad m) => ArrowSchedule System (Schedule m) where+ system s = Schedule $ \cs ->+ let (dynS, _, cs') = runSystem s cs+ go dynSAcc i = AccessT $ do+ w <- get+ let (o, v, a, dynSAcc') = runSystemDyn dynSAcc (W.entities w) i+ ((), w') = runIdentity $ runAccessT a w {W.entities = V.unview v (W.entities w)}+ put w'+ return (o, DynamicSchedule $ go dynSAcc')+ in (DynamicSchedule $ go dynS, cs') -access :: (Monad m) => (i -> AccessT m o) -> Schedule m i o-access f = Schedule $ \cs -> (f, cs)+delay :: (Monad m) => a -> Schedule m a a+delay d = Schedule $ \cs -> (delayDyn d, cs) -task :: (Monad m) => (i -> m o) -> Schedule m i o-task f = Schedule $ \cs -> (AccessT Prelude.. lift Prelude.. f, cs)+runSchedule :: (Monad m) => Schedule m i o -> World -> i -> m (o, DynamicSchedule m i o, World)+runSchedule s w i = do+ let (f, cs) = runSchedule' s (components $ W.entities w)+ ((o, f'), w') <- runAccessT (runScheduleDyn f i) w {W.entities = (W.entities w) {components = cs}}+ return (o, f', w') +runSchedule_ :: (Monad m) => Schedule m () () -> m ()+runSchedule_ s = void (runSchedule s W.empty ())+ 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+ let go' gAcc wAcc = do+ ((o, g'), wAcc') <- lift $ runAccessT (runScheduleDyn gAcc i) wAcc lift $ evaluate $ rnf wAcc' lift $ f o- loop wAcc'- loop w- in (go, cs')+ go' g' wAcc'+ go' g w+ in (DynamicSchedule go, cs') forever_ :: Schedule IO i o -> Schedule IO i () forever_ s = forever s (const $ pure ())
+ src/Aztecs/ECS/Schedule/Access.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Aztecs.ECS.Schedule.Access (AcessSchedule (..), ArrowAccessSchedule (..)) where++import Aztecs.ECS.Access (AccessT (..))+import Aztecs.ECS.Schedule (ArrowAccessSchedule (..))+import Aztecs.ECS.World.Bundle (Bundle)+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))+import Control.Monad ((>=>))++newtype AcessSchedule m i o = AcessSchedule {runAcessSchedule :: i -> AccessT m o}+ deriving (Functor)++instance (Monad m) => Category (AcessSchedule m) where+ id = AcessSchedule return+ AcessSchedule f . AcessSchedule g = AcessSchedule (g >=> f)++instance (Monad m) => Arrow (AcessSchedule m) where+ arr f = AcessSchedule $ \i -> return $ f i+ first (AcessSchedule f) = AcessSchedule $ \(b, d) -> do+ c <- f b+ return (c, d)++instance (Monad m) => ArrowAccessSchedule Bundle (AccessT m) (AcessSchedule m) where+ access = AcessSchedule
+ src/Aztecs/ECS/Schedule/Access/Class.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE FunctionalDependencies #-}++module Aztecs.ECS.Schedule.Access.Class (ArrowAccessSchedule (..)) where++import Aztecs.ECS.Access (MonadAccess)+import Control.Arrow (Arrow (..))++-- | Schedule arrow that provides access to a `World`.+class (MonadAccess b m, Arrow arr) => ArrowAccessSchedule b m arr | arr -> m where+ -- | Access the `World`.+ access :: (i -> m o) -> arr i o
+ src/Aztecs/ECS/Schedule/Class.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE FunctionalDependencies #-}++module Aztecs.ECS.Schedule.Class (ArrowSchedule (..)) where++import Control.Arrow (Arrow (..))++-- | Schedule arrow that runs systems.+class (Arrow arr) => ArrowSchedule s arr | arr -> s where+ -- | Schedule a system.+ system :: s i o -> arr i o
+ src/Aztecs/ECS/Schedule/Dynamic.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE RecursiveDo #-}++module Aztecs.ECS.Schedule.Dynamic+ ( DynamicSchedule,+ DynamicScheduleT (..),+ )+where++import Aztecs.ECS.Access+import Control.Arrow+import Control.Category+import Control.Monad.Fix+import Prelude hiding (id, (.))++type DynamicSchedule m = DynamicScheduleT (AccessT m)++newtype DynamicScheduleT m i o = DynamicSchedule {runScheduleDyn :: i -> m (o, DynamicScheduleT m i o)}+ deriving (Functor)++instance (Monad m) => Category (DynamicScheduleT m) where+ id = DynamicSchedule $ \i -> pure (i, id)+ DynamicSchedule f . DynamicSchedule g = DynamicSchedule $ \i -> do+ (b, g') <- g i+ (c, f') <- f b+ return (c, f' . g')++instance (Monad m) => Arrow (DynamicScheduleT m) where+ arr f = DynamicSchedule $ \i -> pure (f i, arr f)+ first (DynamicSchedule f) = DynamicSchedule $ \(b, d) -> do+ (c, f') <- f b+ return ((c, d), first f')++instance (Monad m) => ArrowChoice (DynamicScheduleT m) where+ left (DynamicSchedule f) = DynamicSchedule $ \i -> case i of+ Left b -> do+ (c, f') <- f b+ return (Left c, left f')+ Right d -> return (Right d, left (DynamicSchedule f))++instance (MonadFix m) => ArrowLoop (DynamicScheduleT m) where+ loop (DynamicSchedule f) = DynamicSchedule $ \b -> do+ rec ((c, d), f') <- f (b, d)+ return (c, loop f')
+ src/Aztecs/ECS/Schedule/Dynamic/Reader.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE RecursiveDo #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.ECS.Schedule.Dynamic.Reader+ ( DynamicReaderSchedule,+ DynamicReaderScheduleT (..),+ )+where++import Aztecs.ECS.Access+import Control.Arrow+import Control.Category+import Control.Monad.Fix+import Prelude hiding (all, any, id, lookup, reads, (.))++type DynamicReaderSchedule m = DynamicReaderScheduleT (AccessT m)++newtype DynamicReaderScheduleT m i o = DynamicReaderSchedule {runScheduleDyn :: i -> m (o, DynamicReaderScheduleT m i o)}+ deriving (Functor)++instance (Monad m) => Category (DynamicReaderScheduleT m) where+ id = DynamicReaderSchedule $ \i -> pure (i, id)+ DynamicReaderSchedule f . DynamicReaderSchedule g = DynamicReaderSchedule $ \i -> do+ (b, g') <- g i+ (c, f') <- f b+ return (c, f' . g')++instance (Monad m) => Arrow (DynamicReaderScheduleT m) where+ arr f = DynamicReaderSchedule $ \i -> pure (f i, arr f)+ first (DynamicReaderSchedule f) = DynamicReaderSchedule $ \(b, d) -> do+ (c, f') <- f b+ return ((c, d), first f')++instance (Monad m) => ArrowChoice (DynamicReaderScheduleT m) where+ left (DynamicReaderSchedule f) = DynamicReaderSchedule $ \i -> case i of+ Left b -> do+ (c, f') <- f b+ return (Left c, left f')+ Right d -> return (Right d, left (DynamicReaderSchedule f))++instance (MonadFix m) => ArrowLoop (DynamicReaderScheduleT m) where+ loop (DynamicReaderSchedule f) = DynamicReaderSchedule $ \b -> do+ rec ((c, d), f') <- f (b, d)+ return (c, loop f')
+ src/Aztecs/ECS/Schedule/Reader.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Aztecs.ECS.Schedule.Reader+ ( ReaderScheduleT (..),+ )+where++import Aztecs.ECS.Access (AccessT (..), runAccessT)+import Aztecs.ECS.Schedule.Dynamic.Reader (DynamicReaderScheduleT (..))+import Aztecs.ECS.Schedule.Reader.Class+import Aztecs.ECS.System.Dynamic.Reader (DynamicReaderSystem (..))+import Aztecs.ECS.System.Reader (ReaderSystem (..))+import Aztecs.ECS.World (World (..))+import Aztecs.ECS.World.Components (Components)+import Control.Arrow+import Control.Category+import Control.Monad.Fix+import Control.Monad.Identity (Identity (runIdentity))+import Control.Monad.State (MonadState (..))+import Prelude hiding (id, (.))++type ReaderSchedule m = ReaderScheduleT (AccessT m)++newtype ReaderScheduleT m i o+ = ReaderSchedule {runReaderSchedule :: Components -> (DynamicReaderScheduleT m i o, Components)}+ deriving (Functor)++instance (Monad m) => Category (ReaderScheduleT m) where+ id = ReaderSchedule $ \cs -> (id, cs)+ ReaderSchedule f . ReaderSchedule g = ReaderSchedule $ \cs ->+ let (g', cs') = g cs+ (f', cs'') = f cs'+ in (f' . g', cs'')++instance (Monad m) => Arrow (ReaderScheduleT m) where+ arr f = ReaderSchedule $ \cs -> (arr f, cs)+ first (ReaderSchedule f) = ReaderSchedule $ \cs -> let (f', cs') = f cs in (first f', cs')++instance (Monad m) => ArrowChoice (ReaderScheduleT m) where+ left (ReaderSchedule f) = ReaderSchedule $ \cs -> let (f', cs') = f cs in (left f', cs')++instance (MonadFix m) => ArrowLoop (ReaderScheduleT m) where+ loop (ReaderSchedule f) = ReaderSchedule $ \cs -> let (f', cs') = f cs in (loop f', cs')++instance (Monad m) => ArrowReaderSchedule ReaderSystem (ReaderSchedule m) where+ reader s = ReaderSchedule $ \cs ->+ let (dynS, _, cs') = runReaderSystem s cs+ go dynSAcc i = AccessT $ do+ w <- get+ let (o, a, dynSAcc') = runReaderSystemDyn dynSAcc (entities w) i+ ((), w') = runIdentity $ runAccessT a w+ put w'+ return (o, DynamicReaderSchedule $ go dynSAcc')+ in (DynamicReaderSchedule $ go dynS, cs')
+ src/Aztecs/ECS/Schedule/Reader/Class.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE FunctionalDependencies #-}++module Aztecs.ECS.Schedule.Reader.Class (ArrowReaderSchedule (..)) where++import Control.Arrow (Arrow (..))++-- | Schedule arrow that runs read-only systems.+class (Arrow arr) => ArrowReaderSchedule s arr | arr -> s where+ -- | Schedule a reader system.+ reader :: s i o -> arr i o
src/Aztecs/ECS/System.hs view
@@ -4,29 +4,34 @@ {-# LANGUAGE MultiParamTypeClasses #-} module Aztecs.ECS.System- ( -- * Systems- System (..),+ ( System (..), ArrowReaderSystem (..), ArrowSystem (..),+ ArrowQueueSystem (..),+ fromReader, ) where +import Aztecs.ECS.Access (Access) 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.Class (ArrowSystem (..))+import Aztecs.ECS.System.Dynamic (DynamicSystem (..), fromDynReaderSystem, raceDyn) import Aztecs.ECS.System.Dynamic.Class (ArrowDynamicSystem (..)) import Aztecs.ECS.System.Dynamic.Reader.Class (ArrowDynamicReaderSystem (..))+import Aztecs.ECS.System.Queue (ArrowQueueSystem (..))+import Aztecs.ECS.System.Reader (ReaderSystem (..)) 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.Bundle (Bundle) import Aztecs.ECS.World.Components (Components)-import Control.Arrow (Arrow (..))-import Control.Category (Category (..))+import Control.Arrow+import Control.Category import qualified Data.Foldable as F-import Prelude hiding (all, filter, map, (.))-import qualified Prelude hiding (filter, map)+import Prelude hiding (all, filter, id, map, (.))+import qualified Prelude hiding (filter, id, map) -- | System to process entities. newtype System i o = System@@ -36,24 +41,28 @@ deriving (Functor) instance Category System where- id = System $ \cs -> (DynamicSystem $ \_ i -> (i, mempty, pure ()), mempty, cs)+ id = System $ \cs -> (DynamicSystem $ \_ i -> (i, mempty, pure (), id), 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)+ arr f = System $ \cs -> (DynamicSystem $ \_ i -> (f i, mempty, pure (), arr f), 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''- )+ dynS = if Q.disjoint rwsA rwsB then dynF &&& dynG else raceDyn dynF dynG+ in (dynS, rwsA <> rwsB, cs'') +instance ArrowChoice System where+ left (System f) = System $ \cs -> let (f', rwsF, cs') = f cs in (left f', rwsF, cs')++instance ArrowLoop System where+ loop (System f) = System $ \cs -> let (f', rwsF, cs') = f cs in (loop f', rwsF, 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')@@ -82,4 +91,10 @@ 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)++instance ArrowQueueSystem Bundle Access System where+ queue f = System $ \cs -> (queue f, mempty, cs)++fromReader :: ReaderSystem i o -> System i o+fromReader (ReaderSystem f) = System $ \cs ->+ let (f', rs, cs') = f cs in (fromDynReaderSystem f', ReadsWrites rs mempty, cs')
src/Aztecs/ECS/System/Class.hs view
@@ -2,7 +2,6 @@ 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)@@ -23,6 +22,3 @@ 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
@@ -1,50 +1,100 @@+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} -module Aztecs.ECS.System.Dynamic (DynamicSystem (..), raceDyn) where+module Aztecs.ECS.System.Dynamic+ ( DynamicSystem (..),+ ArrowDynamicReaderSystem (..),+ ArrowDynamicSystem (..),+ ArrowQueueSystem (..),+ raceDyn,+ fromDynReaderSystem,+ )+where import Aztecs.ECS.Access (Access)+import Aztecs.ECS.Query.Dynamic (DynamicQuery)+import Aztecs.ECS.Query.Dynamic.Reader (DynamicQueryReader) import Aztecs.ECS.System.Dynamic.Class (ArrowDynamicSystem (..))+import Aztecs.ECS.System.Dynamic.Reader (DynamicReaderSystem (..)) 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 Aztecs.ECS.System.Queue (ArrowQueueSystem (..))+import Aztecs.ECS.View (View)+import qualified Aztecs.ECS.View as V+import Aztecs.ECS.World.Bundle (Bundle)+import Aztecs.ECS.World.Entities (Entities (..))+import Control.Arrow+import Control.Category import Control.Parallel (par)+import Data.Maybe (fromMaybe)+import Prelude hiding (id, (.)) 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 ()))+ runSystemDyn :: Entities -> i -> (o, View, Access (), DynamicSystem i o) } deriving (Functor) instance Category DynamicSystem where- id = DynamicSystem $ \_ i -> (i, mempty, pure ())+ id = DynamicSystem $ \_ i -> (i, mempty, pure (), id) 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)+ let (b, gView, gAccess, g') = g w i+ (a, fView, fAccess, f') = f w b+ in (a, gView <> fView, gAccess >> fAccess, f' . g') 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)+ arr f = DynamicSystem $ \_ i -> (f i, mempty, pure (), arr f)+ first (DynamicSystem f) = DynamicSystem $ \w (i, x) ->+ let (a, v, access, f') = f w i in ((a, x), v, access, first f') -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 ArrowChoice DynamicSystem where+ left (DynamicSystem f) = DynamicSystem $ \w i -> case i of+ Left b -> let (c, v, access, f') = f w b in (Left c, v, access, left f')+ Right d -> (Right d, mempty, pure (), left (DynamicSystem f)) -instance ArrowDynamicSystem DynamicSystem where- runArrowSystemDyn = DynamicSystem+instance ArrowLoop DynamicSystem where+ loop (DynamicSystem f) = DynamicSystem $ \w b ->+ let ((c, d), v, access, f') = f w (b, d) in (c, v, access, loop f') +instance ArrowDynamicReaderSystem DynamicQueryReader DynamicSystem where+ allDyn cIds q = fromDynReaderSystem $ allDyn cIds q+ filterDyn cIds qf q = fromDynReaderSystem $ filterDyn cIds qf q++instance ArrowDynamicSystem DynamicQuery DynamicSystem where+ mapDyn cIds q = DynamicSystem $ \w i ->+ let !v = V.view cIds $ archetypes w+ (o, v') = V.allDyn i q v+ in (o, v', pure (), mapDyn cIds q)+ mapSingleDyn cIds q = DynamicSystem $ \w i ->+ let s =+ mapSingleMaybeDyn cIds q+ >>> arr (fromMaybe (error "Expected a single matching entity."))+ in runSystemDyn s w i+ mapSingleMaybeDyn cIds q = DynamicSystem $ \w i ->+ let !res = V.viewSingle cIds $ archetypes w+ (res', v'') = case res of+ Just v -> let (o, v') = V.singleDyn i q v in (o, v')+ Nothing -> (Nothing, mempty)+ in (res', v'', pure (), mapSingleMaybeDyn cIds q)+ filterMapDyn cIds q f = DynamicSystem $ \w i ->+ let !v = V.filterView cIds f $ archetypes w+ (o, v') = V.allDyn i q v+ in (o, v', pure (), filterMapDyn cIds q f)++instance ArrowQueueSystem Bundle Access DynamicSystem where+ queue f = DynamicSystem $ \_ i -> ((), mempty, f i, queue f)+ 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)+ (a, v, fAccess, f') = fa+ (b, v', gAccess, g') = gbPar+ in ((a, b), v <> v', fAccess >> gAccess, raceDyn f' g')++fromDynReaderSystem :: DynamicReaderSystem i o -> DynamicSystem i o+fromDynReaderSystem (DynamicReaderSystem f) = DynamicSystem $ \w i ->+ let (o, access, f') = f w i in (o, mempty, access, fromDynReaderSystem f')
src/Aztecs/ECS/System/Dynamic/Class.hs view
@@ -1,80 +1,21 @@-{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FunctionalDependencies #-} -module Aztecs.ECS.System.Dynamic.Class- ( ArrowDynamicSystem (..),- DynamicSystem,- mapDyn',- mapSingleDyn',- mapSingleMaybeDyn',- filterMapDyn',- queueDyn',- )-where+module Aztecs.ECS.System.Dynamic.Class (ArrowDynamicSystem (..)) 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-+class ArrowDynamicSystem q arr | arr -> q where -- | Map all matching entities, storing the updated entities.- mapDyn :: Set ComponentID -> DynamicQuery i o -> arr i [o]- mapDyn cIds q = runArrowSystemDyn $ mapDyn' cIds q+ mapDyn :: Set ComponentID -> q i o -> arr i [o] - mapSingleDyn :: Set ComponentID -> DynamicQuery i o -> arr i o- mapSingleDyn cIds q = runArrowSystemDyn $ mapSingleDyn' cIds q+ mapSingleDyn :: Set ComponentID -> q i o -> arr i o - mapSingleMaybeDyn :: Set ComponentID -> DynamicQuery i o -> arr i (Maybe o)- mapSingleMaybeDyn cIds q = runArrowSystemDyn $ mapSingleMaybeDyn' cIds q+ mapSingleMaybeDyn :: Set ComponentID -> q i o -> arr i (Maybe o) filterMapDyn :: Set ComponentID ->- DynamicQuery i o ->+ q 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
@@ -1,60 +1,70 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-} module Aztecs.ECS.System.Dynamic.Reader- ( -- * Dynamic Systems- DynamicReaderSystem (..),+ ( DynamicReaderSystem (..), ArrowDynamicReaderSystem (..),+ ArrowQueueSystem (..), raceDyn, ) where -import Aztecs.ECS.Component (ComponentID)+import Aztecs.ECS.Access (Access) import Aztecs.ECS.Query.Dynamic.Reader (DynamicQueryReader) import Aztecs.ECS.System.Dynamic.Reader.Class (ArrowDynamicReaderSystem (..))+import Aztecs.ECS.System.Queue (ArrowQueueSystem (..)) 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 Aztecs.ECS.World.Bundle (Bundle)+import Aztecs.ECS.World.Entities (Entities (..))+import Control.Arrow+import Control.Category import Control.Parallel (par)-import Data.Set (Set)+import Prelude hiding (id, (.)) newtype DynamicReaderSystem i o = DynamicReaderSystem { -- | Run a dynamic system producing some output- runReaderSystemDyn :: World -> i -> o+ runReaderSystemDyn :: Entities -> i -> (o, Access (), DynamicReaderSystem 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+ id = DynamicReaderSystem $ \_ i -> (i, pure (), id)+ DynamicReaderSystem f . DynamicReaderSystem g = DynamicReaderSystem $ \w i ->+ let (b, gAccess, g') = g w i+ (c, fAccess, f') = f w b+ in (c, gAccess >> fAccess, f' . g') 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)+ arr f = DynamicReaderSystem $ \_ i -> (f i, pure (), arr f)+ first (DynamicReaderSystem f) = DynamicReaderSystem $ \w (i, x) ->+ let (a, access, f') = f w i in ((a, x), access, first f') -instance ArrowDynamicReaderSystem DynamicReaderSystem where- allDyn cIds q = DynamicReaderSystem $ allDyn' cIds q- filterDyn cIds q f = DynamicReaderSystem $ filterDyn' cIds q f+instance ArrowChoice DynamicReaderSystem where+ left (DynamicReaderSystem f) = DynamicReaderSystem $ \w i -> case i of+ Left b -> let (c, access, f') = f w b in (Left c, access, left f')+ Right d -> (Right d, pure (), left (DynamicReaderSystem f)) +instance ArrowLoop DynamicReaderSystem where+ loop (DynamicReaderSystem f) = DynamicReaderSystem $ \w b ->+ let ((c, d), access, f') = f w (b, d) in (c, access, loop f')++instance ArrowDynamicReaderSystem DynamicQueryReader DynamicReaderSystem where+ allDyn cIds q = DynamicReaderSystem $ \w i ->+ let !v = V.view cIds $ archetypes w in (V.readAllDyn i q v, pure (), allDyn cIds q)+ filterDyn cIds q f = DynamicReaderSystem $ \w i ->+ let !v = V.filterView cIds f $ archetypes w+ in (V.readAllDyn i q v, pure (), filterDyn cIds q f)++instance ArrowQueueSystem Bundle Access DynamicReaderSystem where+ queue f = DynamicReaderSystem $ \_ i -> let !a = f i in ((), a, queue 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+ (a, fAccess, f') = fa+ (b, gAccess, g') = gbPar+ in ((a, b), fAccess >> gAccess, raceDyn f' g')
src/Aztecs/ECS/System/Dynamic/Reader/Class.hs view
@@ -1,17 +1,18 @@+{-# LANGUAGE FunctionalDependencies #-}+ 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]+class (Arrow arr) => ArrowDynamicReaderSystem q arr | arr -> q where+ allDyn :: Set ComponentID -> q i o -> arr i [o] - filterDyn :: Set ComponentID -> DynamicQueryReader i o -> (Node -> Bool) -> arr i [o]+ filterDyn :: Set ComponentID -> q i o -> (Node -> Bool) -> arr i [o] - singleDyn :: Set ComponentID -> DynamicQueryReader () a -> arr () a+ singleDyn :: Set ComponentID -> q () a -> arr () a singleDyn cIds q = allDyn cIds q >>> arr
+ src/Aztecs/ECS/System/Queue.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Aztecs.ECS.System.Queue (QueueSystem (..), ArrowQueueSystem (..)) where++import Aztecs.ECS.Access (Access)+import Aztecs.ECS.System.Queue.Class (ArrowQueueSystem (..))+import Aztecs.ECS.World.Bundle (Bundle)+import Control.Arrow (Arrow (..))+import Control.Category (Category (..))++-- | System that can queue `Access` to a `World`.+newtype QueueSystem i o = QueueSystem {runQueueSystem :: i -> (o, Access ())}+ deriving (Functor)++instance Category QueueSystem where+ id = QueueSystem $ \i -> (i, pure ())+ QueueSystem f . QueueSystem g = QueueSystem $ \i ->+ let (b, access) = g i+ (c, access') = f b+ in (c, access >> access')++instance Arrow QueueSystem where+ arr f = QueueSystem $ \i -> (f i, pure ())+ first (QueueSystem f) = QueueSystem $ \(b, d) ->+ let (c, access) = f b in ((c, d), access)++instance ArrowQueueSystem Bundle Access QueueSystem where+ queue f = QueueSystem $ \i -> let !a = f i in ((), a)
+ src/Aztecs/ECS/System/Queue/Class.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE FunctionalDependencies #-}++module Aztecs.ECS.System.Queue.Class (ArrowQueueSystem (..)) where++import Aztecs.ECS.Access (MonadAccess)+import Control.Arrow (Arrow (..))++class (MonadAccess b m, Arrow arr) => ArrowQueueSystem b m arr | arr -> m where+ -- | Queue an `Access` to happen after this system schedule.+ queue :: (i -> m ()) -> arr i ()
src/Aztecs/ECS/System/Reader.hs view
@@ -4,39 +4,27 @@ {-# LANGUAGE MultiParamTypeClasses #-} module Aztecs.ECS.System.Reader- ( -- * Systems- ReaderSystem (..),- queue,-- -- ** Queries-- -- *** Reading- all,- filter,- single,-- -- *** Writing- map,- map_,- filterMap,- mapSingle,+ ( ReaderSystem (..),+ ArrowReaderSystem (..),+ ArrowQueueSystem (..), ) where +import Aztecs.ECS.Access (Access) 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 Aztecs.ECS.System.Queue (ArrowQueueSystem (..))+import Aztecs.ECS.System.Reader.Class (ArrowReaderSystem (..)) import qualified Aztecs.ECS.World.Archetype as A import Aztecs.ECS.World.Archetypes (Node (..))+import Aztecs.ECS.World.Bundle (Bundle) import Aztecs.ECS.World.Components (ComponentID, Components)-import Control.Arrow (Arrow (..))-import Control.Category (Category (..))+import Control.Arrow+import Control.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)+import Prelude hiding (id, (.)) -- | System to process entities. newtype ReaderSystem i o = ReaderSystem@@ -55,13 +43,18 @@ 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')+ 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 ArrowChoice ReaderSystem where+ left (ReaderSystem f) = ReaderSystem $ \cs -> let (f', rwsF, cs') = f cs in (left f', rwsF, cs')++instance ArrowLoop ReaderSystem where+ loop (ReaderSystem f) = ReaderSystem $ \cs -> let (f', rwsF, cs') = f cs in (loop f', rwsF, cs')+ instance ArrowReaderSystem QueryReader ReaderSystem where all q = ReaderSystem $ \cs -> let !(rs, cs', dynQ) = runQueryReader q cs in (allDyn rs dynQ, rs, cs')@@ -72,3 +65,6 @@ 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'')++instance ArrowQueueSystem Bundle Access ReaderSystem where+ queue f = ReaderSystem $ \cs -> (queue f, mempty, cs)
src/Aztecs/ECS/View.hs view
@@ -19,12 +19,12 @@ 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 Aztecs.ECS.World.Entities (Entities)+import qualified Aztecs.ECS.World.Entities as E import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Set (Set)@@ -39,10 +39,10 @@ -- | View into all archetypes containing the provided component IDs. view :: Set ComponentID -> Archetypes -> View-view cIds as = View $ AS.lookup cIds as+view cIds as = View $ AS.find cIds as viewSingle :: Set ComponentID -> Archetypes -> Maybe View-viewSingle cIds as = case Map.toList $ AS.lookup cIds as of+viewSingle cIds as = case Map.toList $ AS.find cIds as of [a] -> Just . View $ Map.singleton (fst a) (snd a) _ -> Nothing @@ -52,16 +52,16 @@ (Node -> Bool) -> Archetypes -> View-filterView cIds f as = View $ Map.filter f (AS.lookup cIds as)+filterView cIds f as = View $ Map.filter f (AS.find cIds as) -- | "Un-view" a `View` back into a `World`.-unview :: View -> World -> World-unview v w =- w- { W.archetypes =+unview :: View -> Entities -> Entities+unview v es =+ es+ { E.archetypes = foldl' (\as (aId, n) -> as {AS.nodes = Map.insert aId n (AS.nodes as)})- (W.archetypes w)+ (E.archetypes es) (Map.toList $ viewArchetypes v) }
src/Aztecs/ECS/World.hs view
@@ -6,13 +6,12 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-} module Aztecs.ECS.World ( World (..), empty, spawn,- spawnComponent,- spawnWithId, spawnWithArchetypeId, spawnEmpty, insert,@@ -25,24 +24,15 @@ 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 Aztecs.ECS.Entity+import Aztecs.ECS.World.Archetypes (ArchetypeID)+import Aztecs.ECS.World.Bundle+import Aztecs.ECS.World.Entities (Entities)+import qualified Aztecs.ECS.World.Entities as E+import Control.DeepSeq+import Data.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 GHC.Generics import Prelude hiding (lookup) #if !MIN_VERSION_base(4,20,0)@@ -51,9 +41,7 @@ -- | World of entities and their components. data World = World- { archetypes :: !Archetypes,- components :: !Components,- entities :: !(Map EntityID ArchetypeID),+ { entities :: Entities, nextEntityId :: !EntityID } deriving (Show, Generic, NFData)@@ -62,184 +50,50 @@ empty :: World empty = World- { archetypes = AS.empty,- components = CS.empty,- entities = mempty,+ { entities = E.empty, 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}+ let e = nextEntityId w+ in (e, w {entities = E.spawn e b $ entities w, nextEntityId = EntityID $ unEntityId e + 1}) -- | 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)})+spawnEmpty w = let e = nextEntityId w in (e, w {nextEntityId = EntityID $ unEntityId e + 1}) -- | 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 ->+ (Component a) => 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)- }+ (EntityID, World)+spawnWithArchetypeId aId cId c w =+ let !(e, w') = spawnEmpty w+ in (e, w' {entities = E.spawnWithArchetypeId e aId cId c (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 :: forall a. (Component a) => EntityID -> a -> World -> World+insert e c w = w {entities = E.insert e c (entities w)} -- | 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)}+insertWithId :: (Component a) => EntityID -> ComponentID -> a -> World -> World+insertWithId e cId c w = w {entities = E.insertWithId e cId c (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)+lookup e w = E.lookup e $ entities w -- | 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'}+remove :: forall a. (Component a) => EntityID -> World -> (Maybe a, World)+remove e w = let (a, es) = E.remove e (entities w) in (a, w {entities = es}) -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)+removeWithId :: forall a. (Component a) => EntityID -> ComponentID -> World -> (Maybe a, World)+removeWithId e cId w = let (a, es) = E.removeWithId e cId (entities w) in (a, w {entities = es}) -- | 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)+despawn e w = let (a, es) = E.despawn e (entities w) in (a, w {entities = es})
src/Aztecs/ECS/World/Archetype.hs view
@@ -15,8 +15,6 @@ module Aztecs.ECS.World.Archetype ( Archetype (..), empty,- all,- allMaybe, entities, lookupComponent, lookupStorage,@@ -25,76 +23,24 @@ 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 Aztecs.ECS.Component+import Aztecs.ECS.Entity import qualified Aztecs.ECS.World.Storage as S+import Aztecs.ECS.World.Storage.Dynamic import Control.DeepSeq-import Data.Bifunctor (Bifunctor (..))-import Data.Dynamic (Dynamic, Typeable, fromDynamic, toDyn)+import Data.Dynamic 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)+import GHC.Generics #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}+newtype Archetype = Archetype {storages :: Map ComponentID DynamicStorage} deriving (Show, Generic, NFData) empty :: Archetype@@ -110,109 +56,47 @@ 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+ in arch {storages = Map.insert cId (dynStorage storage) (storages arch)} 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)+ (_, s) : _ -> map (\i -> (EntityID i)) $ entitiesDyn s lookupComponent :: forall a. (Component a) => EntityID -> ComponentID -> Archetype -> Maybe a lookupComponent e cId w = lookupStorage cId w >>= S.lookup (unEntityId e) +-- | Insert a list of components into the archetype, sorted in ascending order by their `EntityID`. 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'}+ let !storage = dynStorage $ S.fromAscList @(StorageT a) (map (\(e, a) -> (unEntityId e, a)) as)+ in arch {storages = Map.insert cId storage (storages arch)} remove :: EntityID -> Archetype -> (Map ComponentID Dynamic, Archetype) remove e arch = foldl' ( \(dynAcc, archAcc) (cId, s) ->- let !(dynA, dynS) = removeDyn s (unEntityId e) (storageDyn s)+ let !(dynA, dynS) = removeDyn (unEntityId e) 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)}- )+ in (dynAcc', archAcc {storages = Map.insert cId dynS $ storages archAcc}) ) (Map.empty, arch) (Map.toList $ storages arch) -removeStorages :: EntityID -> Archetype -> (Map ComponentID AnyStorage, Archetype)+removeStorages :: EntityID -> Archetype -> (Map ComponentID DynamicStorage, Archetype) removeStorages e arch = foldl' ( \(dynAcc, archAcc) (cId, s) ->- let (dynA, dynS) = removeAny s (unEntityId e) (storageDyn s)+ let (dynA, dynS) = removeAny (unEntityId e) 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)}- )+ in (dynAcc', archAcc {storages = Map.insert cId 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
@@ -20,8 +20,8 @@ insertArchetype, lookupArchetypeId, findArchetypeIds,- lookupNode, lookup,+ find, map, adjustArchetype, insert,@@ -32,14 +32,13 @@ import Aztecs.ECS.Component (Component (..), ComponentID) import Aztecs.ECS.Entity (EntityID (..)) import Aztecs.ECS.World.Archetype- ( AnyStorage (..),- Archetype (..),+ ( Archetype (..), insertComponent, removeStorages, ) import qualified Aztecs.ECS.World.Archetype as A+import Aztecs.ECS.World.Storage.Dynamic (insertDyn, removeDyn) import Control.DeepSeq (NFData (..))-import Data.Data (Typeable) import Data.Dynamic (fromDynamic) import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map@@ -116,73 +115,53 @@ [] -> 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)+find :: Set ComponentID -> Archetypes -> Map ArchetypeID Node+find 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 go (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)+ nodes' = Map.insert aId (node {nodeArchetype = arch'}) (nodes archAcc)+ in (a : acc, archAcc {nodes = nodes'})+ in foldl' go ([], 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)+lookup :: ArchetypeID -> Archetypes -> Maybe Node+lookup aId arches = Map.lookup aId (nodes arches) -- | Insert a component into an entity with its `ComponentID`. insert ::- (Component a, Typeable (StorageT a)) =>+ (Component a) => EntityID -> ArchetypeID -> ComponentID -> a -> Archetypes -> (Maybe ArchetypeID, Archetypes)-insert e aId cId c arches = case lookupNode aId arches of+insert e aId cId c arches = case lookup 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)})+ then+ let go n = n {nodeArchetype = insertComponent e cId c (nodeArchetype n)}+ in (Nothing, arches {nodes = Map.adjust go 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)}+ node' = node {nodeArchetype = arch'}+ !arches' = arches {nodes = Map.insert aId node' (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')- }- )+ let go s = insertDyn (unEntityId e) dyn s+ storages' = Map.adjust go itemCId (storages archAcc)+ in archAcc {storages = storages'}+ adjustNode nextNode =+ let nextArch = foldl' f (nodeArchetype nextNode) (Map.toList cs)+ in nextNode {nodeArchetype = insertComponent e cId c nextArch}+ in (Just nextAId, arches' {nodes = Map.adjust adjustNode nextAId (nodes $ arches')}) Nothing -> let !(s, arch') = removeStorages e (nodeArchetype node) !n =@@ -192,58 +171,34 @@ 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')- }- )+ cIds = Set.insert cId (nodeComponentIds node)+ !(nextAId, arches') = insertArchetype cIds n arches+ in let node' =+ node {nodeArchetype = arch', nodeAdd = Map.insert cId nextAId (nodeAdd node)}+ nodes' = Map.insert aId node' (nodes arches')+ in (Just nextAId, arches' {nodes = nodes'}) Nothing -> (Nothing, arches) remove ::- (Component a, Typeable (StorageT a)) =>+ (Component a) => EntityID -> ArchetypeID -> ComponentID -> Archetypes -> (Maybe (a, ArchetypeID), Archetypes)-remove e aId cId arches = case lookupNode aId arches of+remove e aId cId arches = case lookup 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+ go' archAcc (itemCId, dyn) =+ let adjustStorage s = insertDyn (unEntityId e) dyn s+ in archAcc {storages = Map.adjust adjustStorage itemCId (storages archAcc)}+ go nextNode =+ nextNode {nodeArchetype = foldl' go' (nodeArchetype nextNode) (Map.toList cs')} in ( (,nextAId) <$> (a >>= fromDynamic),- arches'- { nodes =- Map.adjust- ( \nextNode ->- nextNode- { nodeArchetype =- foldl'- f- (nodeArchetype nextNode)- (Map.toList cs')- }- )- nextAId- (nodes $ arches')- }+ arches' {nodes = Map.adjust go nextAId (nodes $ arches')} ) Nothing -> let !(cs, arch') = removeStorages e (nodeArchetype node)@@ -256,16 +211,8 @@ 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')- }+ node' = node {nodeArchetype = arch', nodeAdd = Map.insert cId nextAId (nodeAdd node)}+ in ( (,nextAId) <$> (a >>= (\a' -> (fst $ removeDyn (unEntityId e) a') >>= fromDynamic)),+ arches' {nodes = Map.insert aId node' (nodes arches')} ) Nothing -> (Nothing, arches)
+ src/Aztecs/ECS/World/Bundle.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.ECS.World.Bundle+ ( Bundle (..),+ MonoidBundle (..),+ MonoidDynamicBundle (..),+ runBundle,+ )+where++import Aztecs.ECS.Component (Component (..), ComponentID)+import Aztecs.ECS.Entity (EntityID)+import Aztecs.ECS.World.Archetype (Archetype)+import Aztecs.ECS.World.Bundle.Class+import Aztecs.ECS.World.Bundle.Dynamic+import Aztecs.ECS.World.Components (Components)+import qualified Aztecs.ECS.World.Components as CS+import Data.Set (Set)+import qualified Data.Set as Set++-- | Bundle of components.+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)++instance MonoidBundle Bundle where+ bundle :: forall a. (Component a) => a -> Bundle+ bundle a = Bundle $ \cs ->+ let (cId, cs') = CS.insert @a cs in (Set.singleton cId, cs', dynBundle cId a)++instance MonoidDynamicBundle Bundle where+ dynBundle cId c = Bundle $ \cs -> (Set.singleton cId, cs, dynBundle cId c)++-- | Insert a bundle of components into an archetype.+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/Bundle/Class.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}++module Aztecs.ECS.World.Bundle.Class (MonoidBundle (..)) where++import Aztecs.ECS.Component (Component (..))++-- | Monoid bundle of components.+class (Monoid a) => MonoidBundle a where+ -- | Add a component to the bundle.+ bundle :: forall c. (Component c) => c -> a
+ src/Aztecs/ECS/World/Bundle/Dynamic.hs view
@@ -0,0 +1,21 @@+module Aztecs.ECS.World.Bundle.Dynamic+ ( DynamicBundle (..),+ MonoidDynamicBundle (..),+ )+where++import Aztecs.ECS.Entity (EntityID)+import Aztecs.ECS.World.Archetype (Archetype, insertComponent)+import Aztecs.ECS.World.Bundle.Dynamic.Class (MonoidDynamicBundle (..))++-- | Dynamic bundle of components.+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++instance MonoidDynamicBundle DynamicBundle where+ dynBundle cId a = DynamicBundle $ \eId arch -> insertComponent eId cId a arch
+ src/Aztecs/ECS/World/Bundle/Dynamic/Class.hs view
@@ -0,0 +1,9 @@+module Aztecs.ECS.World.Bundle.Dynamic.Class (MonoidDynamicBundle (..)) where++import Aztecs.ECS.Component (Component (..))+import Aztecs.ECS.World.Components (ComponentID)++-- | Monoid bundle of dynamic components.+class MonoidDynamicBundle a where+ -- | Add a component to the bundle by its `ComponentID`.+ dynBundle :: (Component c) => ComponentID -> c -> a
+ src/Aztecs/ECS/World/Entities.hs view
@@ -0,0 +1,215 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.ECS.World.Entities+ ( Entities (..),+ empty,+ spawn,+ spawnComponent,+ spawnWithId,+ spawnWithArchetypeId,+ insert,+ insertWithId,+ lookup,+ remove,+ removeWithId,+ despawn,+ )+where++import Aztecs.ECS.Component+import Aztecs.ECS.Entity+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.Bundle+import Aztecs.ECS.World.Bundle.Dynamic+import Aztecs.ECS.World.Components (Components (..))+import qualified Aztecs.ECS.World.Components as CS+import Control.DeepSeq+import Data.Dynamic+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Maybe+import qualified Data.Set as Set+import Data.Typeable+import GHC.Generics+import Prelude hiding (lookup)++#if !MIN_VERSION_base(4,20,0)+import Data.Foldable (foldl')+#endif++-- | World of entities and their components.+data Entities = Entities+ { archetypes :: !Archetypes,+ components :: !Components,+ entities :: !(Map EntityID ArchetypeID)+ }+ deriving (Show, Generic, NFData)++-- | Empty `World`.+empty :: Entities+empty =+ Entities+ { archetypes = AS.empty,+ components = CS.empty,+ entities = mempty+ }++spawn :: EntityID -> Bundle -> Entities -> Entities+spawn eId b w =+ let (cIds, components', dynB) = unBundle b (components w)+ in case AS.lookupArchetypeId cIds (archetypes w) of+ Just aId -> fromMaybe w $ do+ node <- AS.lookup aId $ archetypes w+ let arch' = runDynamicBundle dynB eId (nodeArchetype node)+ return+ 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 w+ { archetypes = arches,+ entities = Map.insert eId aId (entities w),+ components = components'+ }++-- | Spawn an entity with a component.+spawnComponent :: forall a. (Component a) => EntityID -> a -> Entities -> Entities+spawnComponent e c w = case Map.lookup (typeOf (Proxy @a)) (componentIds (components w)) of+ Just cId -> spawnWithId e cId c w+ Nothing ->+ let (cId, cs) = CS.insert @a (components w) in spawnWithId e cId c w {components = cs}++-- | Spawn an entity with a component and its `ComponentID`.+spawnWithId ::+ forall a.+ (Component a) =>+ EntityID ->+ ComponentID ->+ a ->+ Entities ->+ Entities+spawnWithId e cId c w = 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)}++spawnWithArchetypeId ::+ forall a.+ (Component a) =>+ EntityID ->+ ArchetypeID ->+ ComponentID ->+ a ->+ Entities ->+ Entities+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) => EntityID -> a -> Entities -> Entities+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) => EntityID -> ComponentID -> a -> Entities -> Entities+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 -> Entities -> Maybe a+lookup e w = do+ !cId <- CS.lookup @a $ components w+ !aId <- Map.lookup e $ entities w+ !node <- AS.lookup aId $ archetypes w+ A.lookupComponent e cId $ nodeArchetype node++-- | Insert a component into an entity.+remove :: forall a. (Component a) => EntityID -> Entities -> (Maybe a, Entities)+remove e w =+ let !(cId, components') = CS.insert @a (components w)+ in removeWithId @a e cId w {components = components'}++removeWithId :: forall a. (Component a) => EntityID -> ComponentID -> Entities -> (Maybe a, Entities)+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 -> Entities -> (Map ComponentID Dynamic, Entities)+despawn e w =+ let res = do+ !aId <- Map.lookup e $ entities w+ !node <- AS.lookup 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/Storage.hs view
@@ -14,8 +14,8 @@ -- | Storage with a single component. singleton :: Int -> a -> s a - -- | All components in the storage.- all :: s a -> [(Int, a)]+ -- | List of all components in the storage.+ toList :: s a -> [(Int, a)] -- | Insert a component into the storage. insert :: Int -> a -> s a -> s a@@ -31,7 +31,7 @@ instance (Typeable a, NFData a) => Storage IntMap a where singleton = IntMap.singleton- all = IntMap.toList+ toList = IntMap.toList insert = IntMap.insert lookup = IntMap.lookup fromAscList = IntMap.fromAscList
+ src/Aztecs/ECS/World/Storage/Dynamic.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++module Aztecs.ECS.World.Storage.Dynamic+ ( DynamicStorage (..),+ dynStorage,+ insertDyn,+ removeDyn,+ removeAny,+ entitiesDyn,+ )+where++import qualified Aztecs.ECS.World.Storage as S+import Control.DeepSeq+import Data.Dynamic+import Data.Maybe++data DynamicStorage = DynamicStorage+ { storageDyn :: !Dynamic,+ insertDyn' :: !(Int -> Dynamic -> Dynamic -> Dynamic),+ removeDyn' :: !(Int -> Dynamic -> (Maybe Dynamic, Dynamic)),+ removeAny' :: !(Int -> Dynamic -> (Maybe DynamicStorage, Dynamic)),+ entitiesDyn' :: !(Dynamic -> [Int]),+ storageRnf :: !(Dynamic -> ())+ }++instance Show DynamicStorage where+ show s = "DynamicStorage " ++ show (storageDyn s)++instance NFData DynamicStorage where+ rnf s = storageRnf s (storageDyn s)++dynStorage :: forall s a. (S.Storage s a) => s a -> DynamicStorage+dynStorage s =+ DynamicStorage+ { 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 (dynStorage . S.singleton @s i) a, toDyn b)+ Nothing -> (Nothing, dyn),+ entitiesDyn' = \dyn -> case fromDynamic @(s a) dyn of+ Just s' -> map fst $ S.toList s'+ Nothing -> [],+ storageRnf = \dyn -> maybe () rnf (fromDynamic @(s a) dyn)+ }++insertDyn :: Int -> Dynamic -> DynamicStorage -> DynamicStorage+insertDyn i c s = s {storageDyn = insertDyn' s i c (storageDyn s)}++removeDyn :: Int -> DynamicStorage -> (Maybe Dynamic, DynamicStorage)+removeDyn i s = let (a, s') = removeDyn' s i (storageDyn s) in (a, s {storageDyn = s'})++removeAny :: Int -> DynamicStorage -> (Maybe DynamicStorage, DynamicStorage)+removeAny i s = let (a, s') = removeAny' s i (storageDyn s) in (a, s {storageDyn = s'})++entitiesDyn :: DynamicStorage -> [Int]+entitiesDyn s = entitiesDyn' s (storageDyn s)
src/Aztecs/Hierarchy.hs view
@@ -1,5 +1,7 @@ {-# LANGUAGE Arrows #-}+{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE TypeApplications #-} @@ -8,6 +10,10 @@ Children (..), update, Hierarchy (..),+ toList,+ foldWithKey,+ mapWithKey,+ mapWithAccum, hierarchy, hierarchies, ParentState (..),@@ -15,18 +21,16 @@ ) where -import Aztecs+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 (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.Maybe (mapMaybe) import Data.Set (Set) import qualified Data.Set as Set import GHC.Generics (Generic)@@ -52,7 +56,11 @@ instance Component ChildState update ::- (ArrowQueryReader qr, ArrowQuery q, ArrowReaderSystem qr arr, ArrowSystem q arr) =>+ ( ArrowQueryReader qr,+ ArrowDynamicQueryReader qr,+ ArrowReaderSystem qr arr,+ ArrowQueueSystem b m arr+ ) => arr () () update = proc () -> do parents <-@@ -106,8 +114,9 @@ when (children /= childState) $ do A.insert entity $ ChildState children let added = Set.difference children childState- -- TODO removed = Set.difference childState children+ removed = Set.difference childState children mapM_ (\e -> A.insert e . Parent $ entity) added+ mapM_ (A.remove @_ @_ @Parent) removed Nothing -> do A.insert entity $ ChildState children mapM_ (\e -> A.insert e . Parent $ entity) children@@ -122,12 +131,32 @@ nodeEntity :: a, nodeChildren :: [Hierarchy a] }+ deriving (Functor) +instance Foldable Hierarchy where+ foldMap f n = f (nodeEntity n) <> foldMap (foldMap f) (nodeChildren n)++instance Traversable Hierarchy where+ traverse f n = Node (nodeEntityId n) <$> f (nodeEntity n) <*> traverse (traverse f) (nodeChildren n)++toList :: Hierarchy a -> [(EntityID, a)]+toList n = (nodeEntityId n, nodeEntity n) : concatMap toList (nodeChildren n)++foldWithKey :: (EntityID -> a -> b -> b) -> Hierarchy a -> b -> b+foldWithKey f n b = f (nodeEntityId n) (nodeEntity n) (foldr (foldWithKey f) b (nodeChildren n))++mapWithKey :: (EntityID -> a -> b) -> Hierarchy a -> Hierarchy b+mapWithKey f n = Node (nodeEntityId n) (f (nodeEntityId n) (nodeEntity n)) (map (mapWithKey f) (nodeChildren n))++mapWithAccum :: (EntityID -> a -> b -> (c, b)) -> b -> Hierarchy a -> Hierarchy c+mapWithAccum f b n = case f (nodeEntityId n) (nodeEntity n) b of+ (c, b') -> Node (nodeEntityId n) c (map (mapWithAccum f b') (nodeChildren n))+ hierarchy ::- (ArrowQueryReader q, ArrowReaderSystem q arr) =>+ (ArrowQueryReader q, ArrowDynamicQueryReader q, ArrowReaderSystem q arr) => EntityID -> q i a ->- arr i [Hierarchy a]+ arr i (Maybe (Hierarchy a)) hierarchy e q = proc i -> do children <- S.all@@ -144,9 +173,9 @@ -- | Build all hierarchies of parents to children with the given query. hierarchies ::- (ArrowQueryReader q, ArrowReaderSystem q arr) =>+ (ArrowQueryReader q, ArrowDynamicQueryReader q, ArrowReaderSystem q arr) => q i a ->- arr i [[Hierarchy a]]+ arr i [Hierarchy a] hierarchies q = proc i -> do children <- S.all@@ -160,16 +189,16 @@ i let childMap = Map.fromList children roots <- S.filter Q.entity $ with @Children <> without @Parent -< ()- returnA -< map (`hierarchy'` childMap) roots+ returnA -< mapMaybe (`hierarchy'` childMap) roots -hierarchy' :: EntityID -> Map EntityID (Set EntityID, a) -> [Hierarchy a]+hierarchy' :: EntityID -> Map EntityID (Set EntityID, a) -> Maybe (Hierarchy a) hierarchy' e childMap = case Map.lookup e childMap of Just (cs, a) ->- let bs = concatMap (`hierarchy'` childMap) (Set.toList cs)- in [ Node+ let bs = mapMaybe (`hierarchy'` childMap) (Set.toList cs)+ in Just+ Node { nodeEntityId = e, nodeEntity = a, nodeChildren = bs }- ]- Nothing -> []+ Nothing -> Nothing
src/Aztecs/Time.hs view
@@ -8,10 +8,8 @@ import Data.Word (Word32) import GHC.Generics +-- | Time component. newtype Time = Time {elapsedMS :: Word32}- deriving (Eq, Ord, Num, Show, Generic)+ deriving (Eq, Ord, Num, Show, Generic, NFData) instance Component Time--instance NFData Time where- rnf = rwhnf
src/Aztecs/Transform.hs view
@@ -1,26 +1,103 @@+{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-} -module Aztecs.Transform where+module Aztecs.Transform+ ( -- * Transform+ Transform (..), + -- ** 2D+ Transform2D,+ transform2d,++ -- * Size+ Size (..),++ -- ** 2D+ Size2D,+ size2D,++ -- * Systems+ update,+ update2d,+ propagate,+ propagate2d,+ )+where+ import Aztecs.ECS+import qualified Aztecs.ECS.Access as A+import qualified Aztecs.ECS.Query as Q+import qualified Aztecs.ECS.System as S+import Aztecs.Hierarchy (Hierarchy, hierarchies, mapWithAccum, toList)+import Control.Arrow (Arrow (..), (>>>)) import Control.DeepSeq import GHC.Generics (Generic) import Linear (V2 (..)) -data Transform = Transform- { transformPosition :: !(V2 Int),- transformRotation :: !Float,- transformScale :: !(V2 Int)+-- | Transform component.+data Transform v r = Transform+ { transformTranslation :: !v,+ transformRotation :: !r,+ transformScale :: !v } deriving (Eq, Show, Generic, NFData) -transform :: Transform-transform = Transform (V2 0 0) 0 (V2 1 1)+instance (Num v, Num r) => Semigroup (Transform v r) where+ Transform t1 r1 s1 <> Transform t2 r2 s2 = Transform (t1 + t2) (r1 + r2) (s1 + s2) -instance Component Transform+instance (Num v, Num r) => Monoid (Transform v r) where+ mempty = Transform 0 0 0 -newtype Size = Size {unSize :: V2 Int}+-- | 2D transform component.+type Transform2D = Transform (V2 Int) Int++-- | Empty transform.+transform2d :: Transform2D+transform2d = Transform (V2 0 0) 0 (V2 1 1)++instance Component (Transform (V2 Int) Int)++-- | Size component.+newtype Size v = Size {unSize :: v} deriving (Generic, NFData) -instance Component Size+type Size2D = Size (V2 Int)++size2D :: Size (V2 Integer)+size2D = Size (V2 0 0)++instance Component (Size (V2 Int))++propagateHierarchy :: (Component a, Monoid a) => Hierarchy a -> Hierarchy a+propagateHierarchy = mapWithAccum (\_ t acc -> let t' = t <> acc in (t', t')) mempty++-- | Propagate and update all hierarchies of transform components.+update ::+ forall q arr b m a.+ ( ArrowQueryReader q,+ ArrowDynamicQueryReader q,+ ArrowReaderSystem q arr,+ ArrowQueueSystem b m arr,+ Component a,+ Monoid a+ ) =>+ arr () ()+update = propagate @_ @_ @a >>> S.queue (mapM_ $ mapM_ (uncurry A.insert) . toList)++-- | Propagate and update all hierarchies of transform components.+update2d :: (ArrowQueryReader q, ArrowDynamicQueryReader q, ArrowReaderSystem q arr, ArrowQueueSystem b m arr) => arr () ()+update2d = propagate @_ @_ @Transform2D >>> S.queue (mapM_ $ mapM_ (uncurry A.insert) . toList)++propagate ::+ (ArrowQueryReader q, ArrowDynamicQueryReader q, ArrowReaderSystem q arr, Component a, Monoid a) =>+ arr () [Hierarchy a]+propagate = hierarchies Q.fetch >>> arr (map propagateHierarchy)++propagate2d :: (ArrowQueryReader q, ArrowDynamicQueryReader q, ArrowReaderSystem q arr) => arr () [Hierarchy Transform2D]+propagate2d = propagate
test/Main.hs view
@@ -1,15 +1,18 @@ {-# LANGUAGE ApplicativeDo #-}+{-# LANGUAGE Arrows #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeApplications #-} module Main (main) where import Aztecs import qualified Aztecs.ECS.Query as Q+import qualified Aztecs.ECS.System as S import qualified Aztecs.ECS.World as W import Aztecs.Hierarchy (Children (..), Parent (..)) import qualified Aztecs.Hierarchy as Hierarchy-import Control.Arrow ((&&&))+import Control.Arrow (returnA, (&&&)) import Control.DeepSeq import qualified Data.Set as Set import GHC.Generics@@ -36,17 +39,20 @@ it "queries three components" $ property prop_queryThreeComponents describe "Aztecs.ECS.Hierarchy.update" $ do it "adds Parent components to children" $ property prop_addParents+ it "removes Parent components from removed children" $ property prop_removeParents+ describe "Aztecs.ECS.Schedule" $ do+ it "increments components" prop_quit prop_queryOneComponent :: [X] -> Expectation prop_queryOneComponent xs = let w = foldr (\x -> snd . W.spawn (bundle x)) W.empty xs- (res, _) = Q.all Q.fetch w+ (res, _) = Q.all Q.fetch $ W.entities 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, _) = Q.all (Q.fetch &&& Q.fetch) w+ (res, _) = Q.all (Q.fetch &&& Q.fetch) $ W.entities w in res `shouldMatchList` xys prop_queryThreeComponents :: [(X, Y, Z)] -> Expectation@@ -57,13 +63,46 @@ y <- Q.fetch z <- Q.fetch pure (x, y, z)- (res, _) = Q.all q w+ (res, _) = Q.all q $ W.entities 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''+ (_, _, w'') <- runSchedule (system Hierarchy.update) w' ()+ let (res, _) = Q.all Q.fetch $ W.entities w'' res `shouldMatchList` [Parent e]++prop_removeParents :: Expectation+prop_removeParents = do+ let (_, w) = W.spawnEmpty W.empty+ (e, w') = W.spawn (bundle . Children $ Set.singleton e) w+ (_, _, w'') <- runSchedule (system Hierarchy.update) w' ()+ let w''' = W.insert e (Children Set.empty) w''+ (_, _, w'''') <- runSchedule (system Hierarchy.update) w''' ()+ let (res, _) = Q.all (Q.fetch @_ @Parent) $ W.entities w''''+ res `shouldMatchList` []++prop_quit :: Expectation+prop_quit = do+ let (_, w) = W.spawn (bundle $ X 1) W.empty+ (_, _, w') <- runSchedule quit w ()+ (x, _, _) <- runSchedule quit w' ()+ x `shouldBe` True++quit :: Schedule IO () Bool+quit = proc () -> do+ rec lastShouldQuit <- delay False -< shouldQuit+ x <-+ system $+ S.mapSingle+ ( proc () -> do+ X x <- Q.fetch -< ()+ Q.set -< X $ x + 1+ returnA -< x+ )+ -<+ ()+ let shouldQuit = (lastShouldQuit || x > 1)+ returnA -< shouldQuit