{-# LANGUAGE AllowAmbiguousTypes #-}

module Mischief.ECS.World.Utils where

import Control.Concurrent.STM
import Control.Monad
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.Primitive (PrimMonad (..))
import Control.Monad.Reader.Class (MonadReader (..), asks)
import Control.Monad.Trans (MonadTrans (..))
import Control.Monad.Trans.Reader (ReaderT (runReaderT))
import Data.Bifunctor qualified
import Data.IORef
import Data.List
import Data.Map qualified as Map
import Data.Maybe (fromMaybe, isNothing)
import Data.Proxy
import Data.Set (Set)
import Data.Set qualified as Set
import Data.Text (Text)
import Data.Typeable
import GHC.Stack
import Mischief.ECS.Archetypes
import Mischief.ECS.Components
import Mischief.ECS.Components.Bundle
import Mischief.ECS.Components.Spawn
import Mischief.ECS.Entities
import Mischief.ECS.EntityDef
import Mischief.ECS.EventDef
import Mischief.ECS.Hidden
import Mischief.ECS.Log
import Mischief.ECS.Tables
import Mischief.ECS.Utils
import Mischief.ECS.World
import Mischief.ECS.World.Prefs

-- | Process a 'BundleElement', turning its 'TypeRep' into a 'ComponentId'.
processBundleElement :: World -> ComponentTicks -> (BundleElement ErasedComponent) -> IO ProcessedBundleElement
processBundleElement :: World
-> ComponentTicks
-> BundleElement ErasedComponent
-> IO ProcessedBundleElement
processBundleElement World
world ComponentTicks
ticks BundleElement {rep :: forall e. BundleElement e -> ComponentRep
rep = (ComponentRep ComponentType
r), ErasedComponent
component :: ErasedComponent
component :: forall e. BundleElement e -> e
component} =
  do
    id <- System ComponentId -> World -> IO ComponentId
forall a. System a -> World -> IO a
runSystem (ComponentType -> System ComponentId
getOrAddComponentId ComponentType
r) World
world
    return
      ProcessedBundleElement
        { id,
          component =
            ComponentData
              { value = component,
                ticks
              }
        }
processBundleElement World
world ComponentTicks
ticks BundleElement {rep :: forall e. BundleElement e -> ComponentRep
rep = (PairRep (ComponentType
r, Entity
entity)), ErasedComponent
component :: forall e. BundleElement e -> e
component :: ErasedComponent
component} =
  do
    id <- System ComponentId -> World -> IO ComponentId
forall a. System a -> World -> IO a
runSystem (Pair -> System ComponentId
getOrAddPairId ((ComponentType, Entity) -> Pair
Pair (ComponentType
r, Entity
entity))) World
world
    return
      ProcessedBundleElement
        { id,
          component =
            ComponentData
              { value = component,
                ticks
              }
        }

-- | Process a set of 'BundleElement's into a 'ProcessedBundleData'.
processBundleElements :: World -> ComponentTicks -> Set (BundleElement ErasedComponent) -> IO ProcessedBundleData
processBundleElements :: World
-> ComponentTicks
-> Set (BundleElement ErasedComponent)
-> IO ProcessedBundleData
processBundleElements World
world ComponentTicks
ticks Set (BundleElement ErasedComponent)
elements =
  do
    elements <- (BundleElement ErasedComponent -> IO ProcessedBundleElement)
-> [BundleElement ErasedComponent] -> IO [ProcessedBundleElement]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (World
-> ComponentTicks
-> BundleElement ErasedComponent
-> IO ProcessedBundleElement
processBundleElement World
world ComponentTicks
ticks) (Set (BundleElement ErasedComponent)
-> [BundleElement ErasedComponent]
forall a. Set a -> [a]
Set.toList Set (BundleElement ErasedComponent)
elements)
    return
      ProcessedBundleData {elements}

-- | Combine two 'ProcessedBundleData's, merging their sets of elements.
combineProcessedBundles :: ProcessedBundleData -> ProcessedBundleData -> ProcessedBundleData
combineProcessedBundles :: ProcessedBundleData -> ProcessedBundleData -> ProcessedBundleData
combineProcessedBundles ProcessedBundleData
bundle1 ProcessedBundleData
bundle2 =
  let elements :: [ProcessedBundleElement]
elements = Set ProcessedBundleElement -> [ProcessedBundleElement]
forall a. Set a -> [a]
Set.toList (Set ProcessedBundleElement -> [ProcessedBundleElement])
-> Set ProcessedBundleElement -> [ProcessedBundleElement]
forall a b. (a -> b) -> a -> b
$ Set ProcessedBundleElement
-> Set ProcessedBundleElement -> Set ProcessedBundleElement
forall a. Ord a => Set a -> Set a -> Set a
Set.union ([ProcessedBundleElement] -> Set ProcessedBundleElement
forall a. Ord a => [a] -> Set a
Set.fromList ProcessedBundleData
bundle1.elements) ([ProcessedBundleElement] -> Set ProcessedBundleElement
forall a. Ord a => [a] -> Set a
Set.fromList ProcessedBundleData
bundle2.elements)
   in ProcessedBundleData {[ProcessedBundleElement]
elements :: [ProcessedBundleElement]
elements :: [ProcessedBundleElement]
elements}

-- | Check if a 'ComponentId' is inside a 'ProcessedBundleData'.
isInProcessedBundle :: ProcessedBundleData -> ComponentId -> Bool
isInProcessedBundle :: ProcessedBundleData -> ComponentId -> Bool
isInProcessedBundle ProcessedBundleData {[ProcessedBundleElement]
elements :: ProcessedBundleData -> [ProcessedBundleElement]
elements :: [ProcessedBundleElement]
elements} ComponentId
id = ComponentId
id ComponentId -> [ComponentId] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` (ProcessedBundleElement -> ComponentId)
-> [ProcessedBundleElement] -> [ComponentId]
forall a b. (a -> b) -> [a] -> [b]
map (\ProcessedBundleElement
element -> ProcessedBundleElement
element.id) [ProcessedBundleElement]
elements

-- | Sets the change tick of certain elements of the bundle to the specified 'Tick'.
setChangedTickOfComponents :: ProcessedBundleData -> (ComponentId -> Bool) -> Tick -> ProcessedBundleData
setChangedTickOfComponents :: ProcessedBundleData
-> (ComponentId -> Bool) -> Tick -> ProcessedBundleData
setChangedTickOfComponents ProcessedBundleData {[ProcessedBundleElement]
elements :: ProcessedBundleData -> [ProcessedBundleElement]
elements :: [ProcessedBundleElement]
elements} ComponentId -> Bool
shouldChange Tick
tick =
  ProcessedBundleData
    { elements :: [ProcessedBundleElement]
elements =
        (ProcessedBundleElement -> ProcessedBundleElement)
-> [ProcessedBundleElement] -> [ProcessedBundleElement]
forall a b. (a -> b) -> [a] -> [b]
map
          ( \ProcessedBundleElement {ComponentId
id :: ProcessedBundleElement -> ComponentId
id :: ComponentId
id, component :: ProcessedBundleElement -> ComponentData
component = ComponentData {ErasedComponent
value :: ComponentData -> ErasedComponent
value :: ErasedComponent
value, ticks :: ComponentData -> ComponentTicks
ticks = ComponentTicks {Tick
added :: Tick
added :: ComponentTicks -> Tick
added, Tick
changed :: Tick
changed :: ComponentTicks -> Tick
changed}}} ->
              if ComponentId -> Bool
shouldChange ComponentId
id
                then ProcessedBundleElement {ComponentId
id :: ComponentId
id :: ComponentId
id, component :: ComponentData
component = ComponentData {ErasedComponent
value :: ErasedComponent
value :: ErasedComponent
value, ticks :: ComponentTicks
ticks = ComponentTicks {Tick
added :: Tick
added :: Tick
added, changed :: Tick
changed = Tick
tick}}}
                else ProcessedBundleElement {ComponentId
id :: ComponentId
id :: ComponentId
id, component :: ComponentData
component = ComponentData {ErasedComponent
value :: ErasedComponent
value :: ErasedComponent
value, ticks :: ComponentTicks
ticks = ComponentTicks {Tick
added :: Tick
added :: Tick
added, Tick
changed :: Tick
changed :: Tick
changed}}}
          )
          [ProcessedBundleElement]
elements
    }

-- | Sets the added tick of certain elements of the bundle to the specified 'Tick'.
setAddedTickOfComponents :: ProcessedBundleData -> (ComponentId -> Bool) -> Tick -> ProcessedBundleData
setAddedTickOfComponents :: ProcessedBundleData
-> (ComponentId -> Bool) -> Tick -> ProcessedBundleData
setAddedTickOfComponents ProcessedBundleData {[ProcessedBundleElement]
elements :: ProcessedBundleData -> [ProcessedBundleElement]
elements :: [ProcessedBundleElement]
elements} ComponentId -> Bool
shouldChange Tick
tick =
  ProcessedBundleData
    { elements :: [ProcessedBundleElement]
elements =
        (ProcessedBundleElement -> ProcessedBundleElement)
-> [ProcessedBundleElement] -> [ProcessedBundleElement]
forall a b. (a -> b) -> [a] -> [b]
map
          ( \ProcessedBundleElement {ComponentId
id :: ProcessedBundleElement -> ComponentId
id :: ComponentId
id, component :: ProcessedBundleElement -> ComponentData
component = ComponentData {ErasedComponent
value :: ComponentData -> ErasedComponent
value :: ErasedComponent
value, ticks :: ComponentData -> ComponentTicks
ticks = ComponentTicks {Tick
added :: ComponentTicks -> Tick
added :: Tick
added, Tick
changed :: ComponentTicks -> Tick
changed :: Tick
changed}}} ->
              if ComponentId -> Bool
shouldChange ComponentId
id
                then ProcessedBundleElement {ComponentId
id :: ComponentId
id :: ComponentId
id, component :: ComponentData
component = ComponentData {ErasedComponent
value :: ErasedComponent
value :: ErasedComponent
value, ticks :: ComponentTicks
ticks = ComponentTicks {added :: Tick
added = Tick
tick, Tick
changed :: Tick
changed :: Tick
changed}}}
                else ProcessedBundleElement {ComponentId
id :: ComponentId
id :: ComponentId
id, component :: ComponentData
component = ComponentData {ErasedComponent
value :: ErasedComponent
value :: ErasedComponent
value, ticks :: ComponentTicks
ticks = ComponentTicks {Tick
added :: Tick
added :: Tick
added, Tick
changed :: Tick
changed :: Tick
changed}}}
          )
          [ProcessedBundleElement]
elements
    }

removeComponentFromProcessedBundle :: ComponentId -> ProcessedBundleData -> ProcessedBundleData
removeComponentFromProcessedBundle :: ComponentId -> ProcessedBundleData -> ProcessedBundleData
removeComponentFromProcessedBundle ComponentId
componentId ProcessedBundleData
bundle =
  do
    let elements :: [ProcessedBundleElement]
elements = (ProcessedBundleElement -> Bool)
-> [ProcessedBundleElement] -> [ProcessedBundleElement]
forall a. (a -> Bool) -> [a] -> [a]
filter (\ProcessedBundleElement
x -> ProcessedBundleElement
x.id ComponentId -> ComponentId -> Bool
forall a. Eq a => a -> a -> Bool
/= ComponentId
componentId) ProcessedBundleData
bundle.elements
     in ProcessedBundleData {[ProcessedBundleElement]
elements :: [ProcessedBundleElement]
elements :: [ProcessedBundleElement]
elements}

tryGetEntityRelCollection :: forall c. (Component c) => World -> Entity -> IO (Maybe (Maybe [Result (Rel c)]))
tryGetEntityRelCollection :: forall c.
Component c =>
World -> Entity -> IO (Maybe (Maybe [Result (Rel c)]))
tryGetEntityRelCollection World
world Entity
entity =
  do
    componentId <- TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c) World
world.components
    case componentId of
      Maybe ComponentId
Nothing -> Maybe (Maybe [Result (Rel c)])
-> IO (Maybe (Maybe [Result (Rel c)]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Maybe [Result (Rel c)])
forall a. Maybe a
Nothing
      Just ComponentId
componentId -> do
        pointer <- Entity -> Entities -> IO (Maybe (IORef EntityPointer))
getPointer Entity
entity World
world.entities
        case pointer of
          Maybe (IORef EntityPointer)
Nothing -> do
            Maybe (Maybe [Result (Rel c)])
-> IO (Maybe (Maybe [Result (Rel c)]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Maybe [Result (Rel c)])
forall a. Maybe a
Nothing
          Just IORef EntityPointer
pointer ->
            do
              pointer <- IORef EntityPointer -> IO EntityPointer
forall a. IORef a -> IO a
readIORef IORef EntityPointer
pointer
              res <- tryGetRelCollectionFromTables world.tables entity pointer componentId
              return $ Just res

tryGetEntityComponent :: forall c. (Component c) => World -> Entity -> IO (Maybe (Maybe c))
tryGetEntityComponent :: forall c. Component c => World -> Entity -> IO (Maybe (Maybe c))
tryGetEntityComponent World
world Entity
entity =
  do
    pointer <- Entity -> Entities -> IO (Maybe (IORef EntityPointer))
getPointer Entity
entity World
world.entities

    case pointer of
      Maybe (IORef EntityPointer)
Nothing -> Maybe (Maybe c) -> IO (Maybe (Maybe c))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Maybe c)
forall a. Maybe a
Nothing
      Just IORef EntityPointer
pointer ->
        do
          componentId <- TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c) World
world.components
          case componentId of
            Maybe ComponentId
Nothing -> Maybe (Maybe c) -> IO (Maybe (Maybe c))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (Maybe c) -> IO (Maybe (Maybe c)))
-> Maybe (Maybe c) -> IO (Maybe (Maybe c))
forall a b. (a -> b) -> a -> b
$ Maybe c -> Maybe (Maybe c)
forall a. a -> Maybe a
Just Maybe c
forall a. Maybe a
Nothing
            Just ComponentId
componentId -> do
              pointer <- IORef EntityPointer -> IO EntityPointer
forall a. IORef a -> IO a
readIORef IORef EntityPointer
pointer
              res <- tryGetComponentFromTables world.tables pointer componentId
              return $ Just res

tryGetEntityRel :: forall c. (Component c) => Entity -> World -> Entity -> IO (Maybe (Maybe c))
tryGetEntityRel :: forall c.
Component c =>
Entity -> World -> Entity -> IO (Maybe (Maybe c))
tryGetEntityRel Entity
target World
world Entity
entity =
  do
    pointer <- Entity -> Entities -> IO (Maybe (IORef EntityPointer))
getPointer Entity
entity World
world.entities

    case pointer of
      Maybe (IORef EntityPointer)
Nothing -> Maybe (Maybe c) -> IO (Maybe (Maybe c))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Maybe c)
forall a. Maybe a
Nothing
      Just IORef EntityPointer
pointer ->
        do
          componentId <- TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c) World
world.components
          case componentId of
            Maybe ComponentId
Nothing -> Maybe (Maybe c) -> IO (Maybe (Maybe c))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Maybe c)
forall a. Maybe a
Nothing
            Just (ComponentId (# Word#
id, Maybe Entity
_ #)) -> do
              pointer <- IORef EntityPointer -> IO EntityPointer
forall a. IORef a -> IO a
readIORef IORef EntityPointer
pointer
              res <- tryGetComponentFromTables world.tables pointer (ComponentId (# id, Just target #))
              return $ Just res

tryGetRelCollections :: forall c. (Component c) => World -> [ArchetypeId] -> IO [(Entity, [Result (Rel c)])]
tryGetRelCollections :: forall c.
Component c =>
World -> [ArchetypeId] -> IO [(Entity, [Result (Rel c)])]
tryGetRelCollections World
world [ArchetypeId]
archetypes =
  do
    componentId <- TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c) World
world.components
    case componentId of
      Maybe ComponentId
Nothing -> [(Entity, [Result (Rel c)])] -> IO [(Entity, [Result (Rel c)])]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []
      Just ComponentId
componentId ->
        Tables
-> [ArchetypeId] -> ComponentId -> IO [(Entity, [Result (Rel c)])]
forall c.
Component c =>
Tables
-> [ArchetypeId] -> ComponentId -> IO [(Entity, [Result (Rel c)])]
tryGetRelCollectionsFromTables World
world.tables [ArchetypeId]
archetypes ComponentId
componentId

tryGetComponents :: forall c. (Component c) => World -> [ArchetypeId] -> IO [(Entity, Result c)]
tryGetComponents :: forall c.
Component c =>
World -> [ArchetypeId] -> IO [(Entity, Result c)]
tryGetComponents World
world [ArchetypeId]
archetypes =
  do
    componentId <- TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c) World
world.components
    case componentId of
      Maybe ComponentId
Nothing -> [(Entity, Result c)] -> IO [(Entity, Result c)]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []
      Just ComponentId
componentId ->
        Tables -> [ArchetypeId] -> ComponentId -> IO [(Entity, Result c)]
forall c.
Component c =>
Tables -> [ArchetypeId] -> ComponentId -> IO [(Entity, Result c)]
tryGetComponentsFromTables World
world.tables [ArchetypeId]
archetypes ComponentId
componentId

tryGetEntities :: World -> [ArchetypeId] -> IO [Entity]
tryGetEntities :: World -> [ArchetypeId] -> IO [Entity]
tryGetEntities World
world = Tables -> [ArchetypeId] -> IO [Entity]
tryGetEntitiesFromTables World
world.tables

tryGetRels :: forall c. (Component c) => Entity -> World -> [ArchetypeId] -> IO [(Entity, Result (Rel c))]
tryGetRels :: forall c.
Component c =>
Entity -> World -> [ArchetypeId] -> IO [(Entity, Result (Rel c))]
tryGetRels Entity
target World
world [ArchetypeId]
archetypes =
  do
    componentId <- TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c) World
world.components
    case componentId of
      Maybe ComponentId
Nothing -> [(Entity, Result (Rel c))] -> IO [(Entity, Result (Rel c))]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []
      Just ComponentId
componentId -> do
        res <- Tables -> [ArchetypeId] -> ComponentId -> IO [(Entity, Result c)]
forall c.
Component c =>
Tables -> [ArchetypeId] -> ComponentId -> IO [(Entity, Result c)]
tryGetComponentsFromTables World
world.tables [ArchetypeId]
archetypes (Maybe Entity -> ComponentId -> ComponentId
setCompIdTarget (Entity -> Maybe Entity
forall a. a -> Maybe a
Just Entity
target) ComponentId
componentId) -- {entity = Just target}
        return $ map (\(Entity
e, Result c
res) -> (Entity
e, (Rel c, Entity) -> Result (Rel c)
forall c. (c, Entity) -> Result c
Result (c -> Entity -> Rel c
forall c. c -> Entity -> Rel c
Rel (Result c -> c
forall c. Result c -> c
value Result c
res) Entity
target, Result c -> Entity
forall c. Result c -> Entity
entityOf Result c
res))) res

tryGetRelsMaybe :: forall c. (Component c) => Entity -> World -> [ArchetypeId] -> IO [(Entity, Maybe (Result (Rel c)))]
tryGetRelsMaybe :: forall c.
Component c =>
Entity
-> World -> [ArchetypeId] -> IO [(Entity, Maybe (Result (Rel c)))]
tryGetRelsMaybe Entity
target World
world [ArchetypeId]
archetypes =
  do
    componentId <- TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c) World
world.components
    case componentId of
      Maybe ComponentId
Nothing -> do
        e <- World -> [ArchetypeId] -> IO [Entity]
tryGetEntities World
world [ArchetypeId]
archetypes
        return $ map (,Nothing) e
      Just ComponentId
componentId -> do
        res <- Tables
-> [ArchetypeId] -> ComponentId -> IO [(Entity, Maybe (Result c))]
forall c.
Component c =>
Tables
-> [ArchetypeId] -> ComponentId -> IO [(Entity, Maybe (Result c))]
tryGetComponentsFromTablesMaybe World
world.tables [ArchetypeId]
archetypes (Maybe Entity -> ComponentId -> ComponentId
setCompIdTarget (Entity -> Maybe Entity
forall a. a -> Maybe a
Just Entity
target) ComponentId
componentId) -- {entity = Just target}
        return $
          map
            ( Data.Bifunctor.second
                (fmap (\Result c
res -> (Rel c, Entity) -> Result (Rel c)
forall c. (c, Entity) -> Result c
Result (c -> Entity -> Rel c
forall c. c -> Entity -> Rel c
Rel (Result c -> c
forall c. Result c -> c
value Result c
res) Entity
target, Result c -> Entity
forall c. Result c -> Entity
entityOf Result c
res)))
            )
            res

tryGetComponentsMaybe :: forall c. (Component c) => World -> [ArchetypeId] -> IO [(Entity, Maybe (Result c))]
tryGetComponentsMaybe :: forall c.
Component c =>
World -> [ArchetypeId] -> IO [(Entity, Maybe (Result c))]
tryGetComponentsMaybe World
world [ArchetypeId]
archetypes =
  do
    componentId <- TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c) World
world.components
    case componentId of
      Maybe ComponentId
Nothing -> do
        e <- World -> [ArchetypeId] -> IO [Entity]
tryGetEntities World
world [ArchetypeId]
archetypes
        return $ map (,Nothing) e
      Just ComponentId
componentId ->
        Tables
-> [ArchetypeId] -> ComponentId -> IO [(Entity, Maybe (Result c))]
forall c.
Component c =>
Tables
-> [ArchetypeId] -> ComponentId -> IO [(Entity, Maybe (Result c))]
tryGetComponentsFromTablesMaybe World
world.tables [ArchetypeId]
archetypes ComponentId
componentId

tryGetTicks :: ComponentId -> World -> [ArchetypeId] -> IO [Maybe ComponentTicks]
tryGetTicks :: ComponentId -> World -> [ArchetypeId] -> IO [Maybe ComponentTicks]
tryGetTicks ComponentId
componentId World
world [ArchetypeId]
archetypes = Tables -> [ArchetypeId] -> ComponentId -> IO [Maybe ComponentTicks]
tryGetTicksFromTables World
world.tables [ArchetypeId]
archetypes ComponentId
componentId

tryGetEntityTicks :: Entity -> ComponentId -> World -> IO (Maybe ComponentTicks)
tryGetEntityTicks :: Entity -> ComponentId -> World -> IO (Maybe ComponentTicks)
tryGetEntityTicks Entity
entity ComponentId
componentId World
world = do
  pointer <- Entity -> Entities -> IO (Maybe (IORef EntityPointer))
getPointer Entity
entity World
world.entities
  case pointer of
    Maybe (IORef EntityPointer)
Nothing -> Maybe ComponentTicks -> IO (Maybe ComponentTicks)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ComponentTicks
forall a. Maybe a
Nothing
    Just IORef EntityPointer
pointer -> do
      pointer <- IORef EntityPointer -> IO EntityPointer
forall a. IORef a -> IO a
readIORef IORef EntityPointer
pointer
      tryGetEntityTicksFromTables world.tables pointer componentId

isAlive :: forall m w. (MonadSystem w m) => Entity -> m Bool
isAlive :: forall (m :: * -> *) w. MonadSystem w m => Entity -> m Bool
isAlive Entity
entity = do
  world <- m World
forall w (m :: * -> *). MonadSystem w m => m World
unsafeGetWorld
  liftIO $ isAliveIO entity world.entities

expect :: (HasCallStack) => forall m w a. (MonadSystem w m) => Text -> Maybe a -> m a
expect :: forall (m :: * -> *) w a.
(HasCallStack, MonadSystem w m) =>
Text -> Maybe a -> m a
expect Text
t Maybe a
a = (HasCallStack => m a) -> m a
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack ((HasCallStack => m a) -> m a) -> (HasCallStack => m a) -> m a
forall a b. (a -> b) -> a -> b
$ do
  case Maybe a
a of
    Maybe a
Nothing -> Text -> m ()
forall w (m :: * -> *).
(HasCallStack, MonadSystem w m) =>
Text -> m ()
panic Text
t m () -> (() -> m a) -> m a
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= m a -> () -> m a
forall a b. a -> b -> a
const m a
forall a. HasCallStack => a
undefined
    Just a
x -> a -> m a
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
x

newtype GetSystem = GetSystem (forall c. (Component c) => Proxy c -> Entity -> System (Maybe c))