packages feed

mischief-ecs-0.2.0.0: src/Mischief/ECS/Repeater.hs

module Mischief.ECS.Repeater (Repeater (..)) where

import Control.Concurrent (threadDelay)
import Control.Concurrent.Async (async)
import Control.Concurrent.STM
import Control.Monad
import Control.Monad.IO.Class
import Data.IORef
import GHC.Float (float2Int)
import Mischief.ECS.Components
import Mischief.ECS.Components.HooksDef
import Mischief.ECS.Hooks
import Mischief.ECS.World
import Mischief.ECS.World.Insert
import Mischief.ECS.World.Query
import Mischief.ECS.World.Query.Markers

data Repeater = Repeater Float (System ())

newtype RepeaterRef = RepeaterRef (IORef Bool) deriving anyclass (Component)

instance Component Repeater where
  onAdd =
    [ hook $ \(HookContext e) -> do
        i <- liftIO (newIORef False)
        Just (Repeater t s) <- single $ mkGet e (C @Repeater)
        insert (RepeaterRef i) e
        world <- unsafeGetWorld
        void $ liftIO $ async $ run world i (float2Int $ 1000000 * t) s
    ]

  onRemove =
    [ hook $ \(HookContext e) -> do
        break <- single $ mkGet e (C @RepeaterRef)
        case break of
          Nothing -> pure ()
          Just (RepeaterRef break) -> liftIO $ writeIORef break False
    ]

run :: World -> IORef Bool -> Int -> System () -> IO ()
run world break t s = do
  b <- liftIO $ readIORef break
  unless b $ do
    liftIO $ threadDelay t

    liftIO $ atomically $ modifyTVar' world.deferredAsync (++ [s])
    run world break t s