packages feed

aztecs-0.5.0.0: src/Data/Aztecs/Access.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Data.Aztecs.Access
  ( Access (..),
    runAccess,
    spawn,
    spawn_,
    insert,
    lookup,
    despawn,
  )
where

import Control.Monad.IO.Class (MonadIO)
import Control.Monad.State.Strict (MonadState (..), StateT (..))
import Data.Aztecs.Component (Component (..))
import Data.Aztecs.Entity (EntityID (..))
import Data.Aztecs.World (World (..))
import qualified Data.Aztecs.World as W
import Data.Aztecs.World.Archetype (Bundle (..))
import Data.Data (Typeable)
import Prelude hiding (all, lookup, map)

-- | Access into the `World`.
newtype Access m a = Access {unAccess :: StateT World m a}
  deriving (Functor, Applicative, Monad, MonadIO)

-- | Run an `Access` on a `World`, returning the output and updated `World`.
runAccess :: (Functor m) => Access m a -> World -> m (a, World)
runAccess a = runStateT $ unAccess a

-- | Spawn an entity with a component.
spawn ::
  (Monad m) =>
  Bundle ->
  Access m EntityID
spawn c = Access $ do
  !w <- get
  let !(e, w') = W.spawn c w
  put w'
  return e

spawn_ :: (Monad m) => Bundle -> Access m ()
spawn_ c = do
  _ <- spawn c
  return ()

-- | Insert a component into an entity.
insert :: (Monad m, Component a, Typeable (StorageT a)) => EntityID -> a -> Access m ()
insert e c = Access $ do
  !w <- get
  let !w' = W.insert e c w
  put w'

lookup :: (Monad m, Component a) => EntityID -> Access m (Maybe a)
lookup e = Access $ do
  !w <- get
  return $ W.lookup e w

despawn :: (Monad m) => EntityID -> Access m ()
despawn e = Access $ do
  !w <- get
  let !(_, w') = W.despawn e w
  put w'