{-# LANGUAGE AllowAmbiguousTypes #-} module Mischief.ECS.App.Systems where import Control.Monad.IO.Class import Data.Foldable import Data.IORef import Data.Map (Map) import Data.Map qualified as Map import GHC.StableName (StableName, eqStableName, hashStableName, makeStableName) import GHC.Stack.Types import Mischief.ECS.App.Schedules import Mischief.ECS.App.SystemDef import Mischief.ECS.Components import Mischief.ECS.Components.Required import Mischief.ECS.Entities import Mischief.ECS.Resources import Mischief.ECS.Utils import Mischief.ECS.World import Mischief.ECS.World.Query import Mischief.ECS.World.Query.Markers import Mischief.ECS.World.Spawn newtype Systems = Systems { Systems -> IORef (Map (ScheduleId, Int) (IORef [(StableName (System ()), SystemId)])) systemMap :: IORef (Map (ScheduleId, Int) (IORef [(StableName (System ()), SystemId)])) } deriving anyclass (Typeable Systems [HookRel Systems] [Hook Systems] Set DefaultComponentType IsExclusive (IsExclusiveRel Systems) (Typeable Systems, IsExclusive (IsExclusiveRel Systems)) => Set DefaultComponentType -> [Hook Systems] -> [Hook Systems] -> [Hook Systems] -> [HookRel Systems] -> [HookRel Systems] -> [HookRel Systems] -> Component Systems forall c. (Typeable c, IsExclusive (IsExclusiveRel c)) => Set DefaultComponentType -> [Hook c] -> [Hook c] -> [Hook c] -> [HookRel c] -> [HookRel c] -> [HookRel c] -> Component c $crequired :: Set DefaultComponentType required :: Set DefaultComponentType $conAdd :: [Hook Systems] onAdd :: [Hook Systems] $conSet :: [Hook Systems] onSet :: [Hook Systems] $conRemove :: [Hook Systems] onRemove :: [Hook Systems] $conAddRel :: [HookRel Systems] onAddRel :: [HookRel Systems] $conSetRel :: [HookRel Systems] onSetRel :: [HookRel Systems] $conRemoveRel :: [HookRel Systems] onRemoveRel :: [HookRel Systems] Component) newtype SystemFunction = SystemFunction {SystemFunction -> System () inner :: System ()} instance Component SystemFunction where required :: Set DefaultComponentType required = forall b. RequiredBundle b => Set DefaultComponentType forall {k} (b :: k). RequiredBundle b => Set DefaultComponentType require @(SystemTick, LastSystemTick) newSystems :: IO Systems newSystems :: IO Systems newSystems = do systemMap <- Map (ScheduleId, Int) (IORef [(StableName (System ()), SystemId)]) -> IO (IORef (Map (ScheduleId, Int) (IORef [(StableName (System ()), SystemId)]))) forall a. a -> IO (IORef a) newIORef Map (ScheduleId, Int) (IORef [(StableName (System ()), SystemId)]) forall k a. Map k a Map.empty return Systems {systemMap} getSystemId' :: (HasCallStack) => ScheduleId -> System () -> StableName (System ()) -> IORef [(StableName (System ()), SystemId)] -> System SystemId getSystemId' :: HasCallStack => ScheduleId -> System () -> StableName (System ()) -> IORef [(StableName (System ()), SystemId)] -> System SystemId getSystemId' ScheduleId schedule System () system StableName (System ()) stableName IORef [(StableName (System ()), SystemId)] list = do list' <- IO [(StableName (System ()), SystemId)] -> System [(StableName (System ()), SystemId)] forall a. IO a -> System a forall (m :: * -> *) a. MonadIO m => IO a -> m a liftIO (IO [(StableName (System ()), SystemId)] -> System [(StableName (System ()), SystemId)]) -> IO [(StableName (System ()), SystemId)] -> System [(StableName (System ()), SystemId)] forall a b. (a -> b) -> a -> b $ IORef [(StableName (System ()), SystemId)] -> IO [(StableName (System ()), SystemId)] forall a. IORef a -> IO a readIORef IORef [(StableName (System ()), SystemId)] list case find (\(StableName (System ()), SystemId) x -> (StableName (System ()), SystemId) -> StableName (System ()) forall a b. (a, b) -> a fst (StableName (System ()), SystemId) x StableName (System ()) -> StableName (System ()) -> Bool forall a b. StableName a -> StableName b -> Bool `eqStableName` StableName (System ()) stableName) list' of Just (StableName (System ()) _, SystemId x) -> SystemId -> System SystemId forall a. a -> System a forall (m :: * -> *) a. Monad m => a -> m a return SystemId x Maybe (StableName (System ()), SystemId) Nothing -> do index <- (SystemFunction, Rel ScheduledIn) -> System Entity forall b. (HasCallStack, Bundle b) => b -> System Entity spawn (System () -> SystemFunction SystemFunction System () system, ScheduledIn -> Entity -> Rel ScheduledIn forall c. c -> Entity -> Rel c Rel ScheduledIn ScheduledIn ScheduleId schedule.id) liftIO $ modifyIORef' list (++ [(stableName, SystemId index)]) return $ SystemId index getSystemId :: (HasCallStack) => ScheduleId -> System () -> System SystemId getSystemId :: HasCallStack => ScheduleId -> System () -> System SystemId getSystemId ScheduleId sch System () system = do Systems {systemMap} <- Maybe Systems -> Systems forall a. HasCallStack => Maybe a -> a unwrap (Maybe Systems -> Systems) -> System (Maybe Systems) -> System Systems forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> (forall c. Component c => System (Maybe c) res @Systems) stableName <- liftIO $ makeStableName system systemMap' <- liftIO $ readIORef systemMap case Map.lookup (sch, hashStableName stableName) systemMap' of Just IORef [(StableName (System ()), SystemId)] x -> HasCallStack => ScheduleId -> System () -> StableName (System ()) -> IORef [(StableName (System ()), SystemId)] -> System SystemId ScheduleId -> System () -> StableName (System ()) -> IORef [(StableName (System ()), SystemId)] -> System SystemId getSystemId' ScheduleId sch System () system StableName (System ()) stableName IORef [(StableName (System ()), SystemId)] x Maybe (IORef [(StableName (System ()), SystemId)]) Nothing -> do l <- IO (IORef [(StableName (System ()), SystemId)]) -> System (IORef [(StableName (System ()), SystemId)]) forall a. IO a -> System a forall (m :: * -> *) a. MonadIO m => IO a -> m a liftIO (IO (IORef [(StableName (System ()), SystemId)]) -> System (IORef [(StableName (System ()), SystemId)])) -> IO (IORef [(StableName (System ()), SystemId)]) -> System (IORef [(StableName (System ()), SystemId)]) forall a b. (a -> b) -> a -> b $ [(StableName (System ()), SystemId)] -> IO (IORef [(StableName (System ()), SystemId)]) forall a. a -> IO (IORef a) newIORef [] liftIO $ modifyIORef' systemMap (Map.insert (sch, hashStableName stableName) l) getSystemId' sch system stableName l removeSystemFromMap' :: StableName (System ()) -> IORef [(StableName (System ()), SystemId)] -> System () removeSystemFromMap' :: StableName (System ()) -> IORef [(StableName (System ()), SystemId)] -> System () removeSystemFromMap' StableName (System ()) stableName IORef [(StableName (System ()), SystemId)] list = do IO () -> System () forall a. IO a -> System a forall (m :: * -> *) a. MonadIO m => IO a -> m a liftIO (IO () -> System ()) -> IO () -> System () forall a b. (a -> b) -> a -> b $ IORef [(StableName (System ()), SystemId)] -> ([(StableName (System ()), SystemId)] -> [(StableName (System ()), SystemId)]) -> IO () forall a. IORef a -> (a -> a) -> IO () modifyIORef' IORef [(StableName (System ()), SystemId)] list (([(StableName (System ()), SystemId)] -> [(StableName (System ()), SystemId)]) -> IO ()) -> ([(StableName (System ()), SystemId)] -> [(StableName (System ()), SystemId)]) -> IO () forall a b. (a -> b) -> a -> b $ ((StableName (System ()), SystemId) -> Bool) -> [(StableName (System ()), SystemId)] -> [(StableName (System ()), SystemId)] forall a. (a -> Bool) -> [a] -> [a] filter (\(StableName (System ()), SystemId) x -> Bool -> Bool not (Bool -> Bool) -> Bool -> Bool forall a b. (a -> b) -> a -> b $ (StableName (System ()), SystemId) -> StableName (System ()) forall a b. (a, b) -> a fst (StableName (System ()), SystemId) x StableName (System ()) -> StableName (System ()) -> Bool forall a b. StableName a -> StableName b -> Bool `eqStableName` StableName (System ()) stableName) removeSystemFromMap :: ScheduleId -> System () -> System () removeSystemFromMap :: ScheduleId -> System () -> System () removeSystemFromMap ScheduleId sch System () system = do Systems {systemMap} <- Maybe Systems -> Systems forall a. HasCallStack => Maybe a -> a unwrap (Maybe Systems -> Systems) -> System (Maybe Systems) -> System Systems forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> (forall c. Component c => System (Maybe c) res @Systems) stableName <- liftIO $ makeStableName system systemMap' <- liftIO $ readIORef systemMap forM_ (Map.lookup (sch, hashStableName stableName) systemMap') (removeSystemFromMap' stableName) systemEntity :: forall sch. (HasCallStack, Schedule sch) => System () -> System Entity systemEntity :: forall {k} (sch :: k). (HasCallStack, Schedule sch) => System () -> System Entity systemEntity System () s = do schId <- forall (sch :: k). Schedule sch => System Entity forall {k} (sch :: k). Schedule sch => System Entity scheduleEntity @sch x <- getSystemId (ScheduleId schId) s return x.id self :: forall m w. (MonadSystem w m) => m Entity self :: forall (m :: * -> *) w. MonadSystem w m => m Entity self = do world <- m World forall w (m :: * -> *). MonadSystem w m => m World unsafeGetWorld let (SystemId sys) = world.systemId return sys data ScheduledIn = ScheduledIn deriving (Typeable ScheduledIn [HookRel ScheduledIn] [Hook ScheduledIn] Set DefaultComponentType IsExclusive (IsExclusiveRel ScheduledIn) (Typeable ScheduledIn, IsExclusive (IsExclusiveRel ScheduledIn)) => Set DefaultComponentType -> [Hook ScheduledIn] -> [Hook ScheduledIn] -> [Hook ScheduledIn] -> [HookRel ScheduledIn] -> [HookRel ScheduledIn] -> [HookRel ScheduledIn] -> Component ScheduledIn forall c. (Typeable c, IsExclusive (IsExclusiveRel c)) => Set DefaultComponentType -> [Hook c] -> [Hook c] -> [Hook c] -> [HookRel c] -> [HookRel c] -> [HookRel c] -> Component c $crequired :: Set DefaultComponentType required :: Set DefaultComponentType $conAdd :: [Hook ScheduledIn] onAdd :: [Hook ScheduledIn] $conSet :: [Hook ScheduledIn] onSet :: [Hook ScheduledIn] $conRemove :: [Hook ScheduledIn] onRemove :: [Hook ScheduledIn] $conAddRel :: [HookRel ScheduledIn] onAddRel :: [HookRel ScheduledIn] $conSetRel :: [HookRel ScheduledIn] onSetRel :: [HookRel ScheduledIn] $conRemoveRel :: [HookRel ScheduledIn] onRemoveRel :: [HookRel ScheduledIn] Component) getSystemTicks :: World -> IO (Tick, Tick) getSystemTicks :: World -> IO (Tick, Tick) getSystemTicks World world = do let (SystemId Entity sys) = World world.systemId System (Tick, Tick) -> World -> IO (Tick, Tick) forall a. System a -> World -> IO a runSystem ( do Just (a, b) <- Query System (LastSystemTick, SystemTick) -> System (Maybe (LastSystemTick, SystemTick)) forall w (m :: * -> *) out. MonadSystem w m => Query m out -> m (Maybe out) single (Query System (LastSystemTick, SystemTick) -> System (Maybe (LastSystemTick, SystemTick))) -> Query System (LastSystemTick, SystemTick) -> System (Maybe (LastSystemTick, SystemTick)) forall a b. (a -> b) -> a -> b $ Entity -> (C LastSystemTick, C SystemTick) -> Query System (LastSystemTick, SystemTick) forall qd out (m :: * -> *). Queryable qd out => Entity -> qd -> Query m out mkGet Entity sys (forall a. C a forall {k} (a :: k). C a C @LastSystemTick, forall a. C a forall {k} (a :: k). C a C @SystemTick) return (a.inner, b.inner) ) World world