{-# LANGUAGE AllowAmbiguousTypes #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}

module Mischief.ECS.World.Insert where

import Control.Exception
import Control.Monad
import Control.Monad.IO.Class
import Data.Foldable (for_)
import Data.IORef
import Data.List hiding (insert)
import Data.Set qualified as Set
import Data.Text qualified as T
import GHC.Base (Int (..))
import GHC.Stack
import Mischief.ECS.Archetypes.Graph
  ( getArchetypeOnInsert,
  )
import Mischief.ECS.Components
import Mischief.ECS.Components.Bundle
import Mischief.ECS.Components.HooksDef (HookContext (..), HookContextRel (..))
import Mischief.ECS.Components.Spawn (ComponentAddHooks (ComponentAddHooks), ComponentAddHooksRel (ComponentAddHooksRel), ComponentSetHooks (ComponentSetHooks), ComponentSetHooksRel (ComponentSetHooksRel), meta)
import Mischief.ECS.Entities
import Mischief.ECS.EventDef
import Mischief.ECS.Events
import Mischief.ECS.Log
import Mischief.ECS.Tables
import Mischief.ECS.Vec qualified as Vec
import Mischief.ECS.World
import Mischief.ECS.World.Change
import Mischief.ECS.World.Prefs
import Mischief.ECS.World.Query
import Mischief.ECS.World.Query.Markers
import Mischief.ECS.World.Utils

data Exception' = Exception' deriving (Int -> Exception' -> ShowS
[Exception'] -> ShowS
Exception' -> String
(Int -> Exception' -> ShowS)
-> (Exception' -> String)
-> ([Exception'] -> ShowS)
-> Show Exception'
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Exception' -> ShowS
showsPrec :: Int -> Exception' -> ShowS
$cshow :: Exception' -> String
show :: Exception' -> String
$cshowList :: [Exception'] -> ShowS
showList :: [Exception'] -> ShowS
Show)

instance Exception Exception'

-- | Insert a bundle of components on an Entity.
--
-- If the entity already contains these components, their values will be
-- updated in-place instead of causing an archetype change.
insert :: (HasCallStack) => forall b. (Bundle b) => b -> Entity -> System ()
insert :: forall b. (HasCallStack, Bundle b) => b -> Entity -> System ()
insert b
bundle Entity
entity =
  do
    world <- System World
forall w (m :: * -> *). MonadSystem w m => m World
unsafeGetWorld
    pointer <- liftIO $ getPointer entity world.entities

    case pointer of
      Maybe (IORef EntityPointer)
Nothing -> Text -> System ()
forall w (m :: * -> *).
(HasCallStack, MonadSystem w m) =>
Text -> m ()
warn (Text -> System ()) -> Text -> System ()
forall a b. (a -> b) -> a -> b
$ Text
"Insertion failed: Entity " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Entity -> Text
forall a. Show a => a -> Text
T.show Entity
entity Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is not alive."
      Just IORef EntityPointer
currentPointer -> do
        let BundleData {Set (BundleElement ErasedComponent)
elements :: Set (BundleElement ErasedComponent)
elements :: forall e. BundleData e -> Set (BundleElement e)
elements, Set (BundleElement ErasedComponent)
resources :: Set (BundleElement ErasedComponent)
resources :: forall e. BundleData e -> Set (BundleElement e)
resources, Set (Entity, BundleData ErasedComponent)
external :: Set (Entity, BundleData ErasedComponent)
external :: forall e. BundleData e -> Set (Entity, BundleData e)
external} = b -> BundleData ErasedComponent
forall b. Bundle b => b -> BundleData ErasedComponent
bundleData b
bundle

        Set (Entity, BundleData ErasedComponent)
-> ((Entity, BundleData ErasedComponent) -> System ()) -> System ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ Set (Entity, BundleData ErasedComponent)
external (((Entity, BundleData ErasedComponent) -> System ()) -> System ())
-> ((Entity, BundleData ErasedComponent) -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \(Entity
e, BundleData ErasedComponent
x) -> do
          forall b. (HasCallStack, Bundle b) => b -> Entity -> System ()
BundleData ErasedComponent -> Entity -> System ()
forall b. Bundle b => b -> Entity -> System ()
insert BundleData ErasedComponent
x Entity
e

        Set (BundleElement ErasedComponent)
-> (BundleElement ErasedComponent -> System ()) -> System ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ Set (BundleElement ErasedComponent)
resources ((BundleElement ErasedComponent -> System ()) -> System ())
-> (BundleElement ErasedComponent -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \BundleElement {component :: forall e. BundleElement e -> e
component = ErasedComponent (c
val :: c)} -> do
          m <- forall c. Component c => System Entity
meta @c
          insert val m

        currentTick <- IO Tick -> System Tick
forall a. IO a -> System a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Tick -> System Tick) -> IO Tick -> System Tick
forall a b. (a -> b) -> a -> b
$ IORef Tick -> IO Tick
forall a. IORef a -> IO a
readIORef World
world.tick

        bundleData <- liftIO $ processBundleElements world ComponentTicks {changed = currentTick, added = currentTick} elements
        let newComponents = [ComponentId] -> [ComponentId]
forall a. Ord a => [a] -> [a]
sort ([ComponentId] -> [ComponentId]) -> [ComponentId] -> [ComponentId]
forall a b. (a -> b) -> a -> b
$ (ProcessedBundleElement -> ComponentId)
-> [ProcessedBundleElement] -> [ComponentId]
forall a b. (a -> b) -> [a] -> [b]
map (\ProcessedBundleElement
x -> ProcessedBundleElement
x.id) ProcessedBundleData
bundleData.elements

        (EntityPointer (# archetypeId, rowIndex #)) <- liftIO $ readIORef currentPointer

        currentTable <- Vec.read world.tables.inner (I# archetypeId)

        ChangeResult {requiredComponentsAdded, newComponents} <-
          if newComponents `isSubsequenceOf` currentTable.components
            -- Simple case, no archetype change.
            then do
              liftIO $ replaceComponentsIntoTable bundleData (Just currentTick) (EntityPointer (# archetypeId, rowIndex #)) currentTable
              pure $ ChangeResult [] []
            -- Complex case, archetype change.
            else do
              newArchetype <- getArchetypeOnInsert (ArchetypeId $ I# archetypeId) newComponents
              changeArchetype entity newArchetype (Just bundleData)

        unless world.prefs.supressEvents $ do
          triggerAddEvent (ProcessedBundleData newComponents) entity
          triggerAddEvent (ProcessedBundleData requiredComponentsAdded) entity
          triggerSetEvent bundleData entity
          triggerSetEvent (ProcessedBundleData requiredComponentsAdded) entity

-- | Insert a bundle of components on an Entity.
--
-- Only the components that the entity doesn't already have will be inserted, and the rest ignored.
insertNew :: forall b. (Bundle b) => b -> Entity -> System ()
insertNew :: forall b. Bundle b => b -> Entity -> System ()
insertNew b
bundle Entity
entity =
  do
    let BundleData {Set (BundleElement ErasedComponent)
elements :: forall e. BundleData e -> Set (BundleElement e)
elements :: Set (BundleElement ErasedComponent)
elements, Set (BundleElement ErasedComponent)
resources :: forall e. BundleData e -> Set (BundleElement e)
resources :: Set (BundleElement ErasedComponent)
resources, Set (Entity, BundleData ErasedComponent)
external :: forall e. BundleData e -> Set (Entity, BundleData e)
external :: Set (Entity, BundleData ErasedComponent)
external} = b -> BundleData ErasedComponent
forall b. Bundle b => b -> BundleData ErasedComponent
bundleData b
bundle
    Set (Entity, BundleData ErasedComponent)
-> ((Entity, BundleData ErasedComponent) -> System ()) -> System ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ Set (Entity, BundleData ErasedComponent)
external (((Entity, BundleData ErasedComponent) -> System ()) -> System ())
-> ((Entity, BundleData ErasedComponent) -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \(Entity
e, BundleData ErasedComponent
s) -> do
      BundleData ErasedComponent -> Entity -> System ()
forall b. Bundle b => b -> Entity -> System ()
insertNew BundleData ErasedComponent
s Entity
e

    world <- System World
forall w (m :: * -> *). MonadSystem w m => m World
unsafeGetWorld

    pointer <- liftIO $ getPointer entity world.entities

    case pointer of
      Maybe (IORef EntityPointer)
Nothing -> Text -> System ()
forall w (m :: * -> *).
(HasCallStack, MonadSystem w m) =>
Text -> m ()
warn (Text -> System ()) -> Text -> System ()
forall a b. (a -> b) -> a -> b
$ Text
"Insertion failed: Entity " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Entity -> Text
forall a. Show a => a -> Text
T.show Entity
entity Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is not alive."
      Just IORef EntityPointer
currentPointer -> do
        Set (BundleElement ErasedComponent)
-> (BundleElement ErasedComponent -> System ()) -> System ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ Set (BundleElement ErasedComponent)
resources ((BundleElement ErasedComponent -> System ()) -> System ())
-> (BundleElement ErasedComponent -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \BundleElement {component :: forall e. BundleElement e -> e
component = ErasedComponent (c
val :: c)} -> do
          m <- forall c. Component c => System Entity
meta @c
          r <- single $ mkGet m (C @c)
          case r of
            Just c
_ -> () -> System ()
forall a. a -> System a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
            Maybe c
Nothing -> c -> Entity -> System ()
forall b. (HasCallStack, Bundle b) => b -> Entity -> System ()
forall b. Bundle b => b -> Entity -> System ()
insert c
val Entity
m

        currentTick <- IO Tick -> System Tick
forall a. IO a -> System a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Tick -> System Tick) -> IO Tick -> System Tick
forall a b. (a -> b) -> a -> b
$ IORef Tick -> IO Tick
forall a. IORef a -> IO a
readIORef World
world.tick

        bundleData <- liftIO $ processBundleElements world ComponentTicks {changed = currentTick, added = currentTick} elements

        (EntityPointer (# archetypeId, _ #)) <- liftIO $ readIORef currentPointer

        currentTable <- Vec.read world.tables.inner (I# archetypeId)

        let newComponents = [ProcessedBundleElement] -> ProcessedBundleData
ProcessedBundleData ([ProcessedBundleElement] -> ProcessedBundleData)
-> [ProcessedBundleElement] -> ProcessedBundleData
forall a b. (a -> b) -> a -> b
$ (ProcessedBundleElement -> Bool)
-> [ProcessedBundleElement] -> [ProcessedBundleElement]
forall a. (a -> Bool) -> [a] -> [a]
filter (\ProcessedBundleElement
c -> ProcessedBundleElement
c.id ComponentId -> [ComponentId] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` Table
currentTable.components) ProcessedBundleData
bundleData.elements

        unless (null newComponents.elements) $ do
          newArchetype <- getArchetypeOnInsert (ArchetypeId $ I# archetypeId) $ map (\ProcessedBundleElement
x -> ProcessedBundleElement
x.id) newComponents.elements
          ChangeResult {requiredComponentsAdded} <- changeArchetype entity newArchetype (Just bundleData)

          unless world.prefs.supressEvents $ do
            triggerAddEvent (ProcessedBundleData requiredComponentsAdded) entity
            triggerAddEvent newComponents entity
            triggerSetEvent (ProcessedBundleData requiredComponentsAdded) entity
            triggerSetEvent newComponents entity

insertIfNeq :: forall b. (BundleEq b) => b -> Entity -> System ()
insertIfNeq :: forall b. BundleEq b => b -> Entity -> System ()
insertIfNeq b
b Entity
entity = do
  let BundleData {Set (BundleElement ErasedComponentEq)
elements :: forall e. BundleData e -> Set (BundleElement e)
elements :: Set (BundleElement ErasedComponentEq)
elements, Set (BundleElement ErasedComponentEq)
resources :: forall e. BundleData e -> Set (BundleElement e)
resources :: Set (BundleElement ErasedComponentEq)
resources, Set (Entity, BundleData ErasedComponentEq)
external :: forall e. BundleData e -> Set (Entity, BundleData e)
external :: Set (Entity, BundleData ErasedComponentEq)
external} = b -> BundleData ErasedComponentEq
forall b. BundleEq b => b -> BundleData ErasedComponentEq
bundleDataEq b
b

  comps <- ((BundleElement ErasedComponentEq -> System Bool)
 -> [BundleElement ErasedComponentEq]
 -> System [BundleElement ErasedComponentEq])
-> [BundleElement ErasedComponentEq]
-> (BundleElement ErasedComponentEq -> System Bool)
-> System [BundleElement ErasedComponentEq]
forall a b c. (a -> b -> c) -> b -> a -> c
flip (BundleElement ErasedComponentEq -> System Bool)
-> [BundleElement ErasedComponentEq]
-> System [BundleElement ErasedComponentEq]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM (Set (BundleElement ErasedComponentEq)
-> [BundleElement ErasedComponentEq]
forall a. Set a -> [a]
Set.toList Set (BundleElement ErasedComponentEq)
elements) ((BundleElement ErasedComponentEq -> System Bool)
 -> System [BundleElement ErasedComponentEq])
-> (BundleElement ErasedComponentEq -> System Bool)
-> System [BundleElement ErasedComponentEq]
forall a b. (a -> b) -> a -> b
$ \BundleElement {ComponentRep
rep :: ComponentRep
rep :: forall e. BundleElement e -> ComponentRep
rep, component :: forall e. BundleElement e -> e
component = ErasedComponentEq (c
val :: c)} -> do
    val' <- case ComponentRep
rep of
      PairRep (ComponentType
_, Entity
target) -> (Rel c -> c) -> Maybe (Rel c) -> Maybe c
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Rel c
x -> Rel c
x.comp) (Maybe (Rel c) -> Maybe c)
-> System (Maybe (Rel c)) -> System (Maybe c)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Query System (Rel c) -> System (Maybe (Rel c))
forall w (m :: * -> *) out.
MonadSystem w m =>
Query m out -> m (Maybe out)
single (Entity -> R c Entity -> Query System (Rel c)
forall qd out (m :: * -> *).
Queryable qd out =>
Entity -> qd -> Query m out
mkGet Entity
entity (forall {k} (a :: k) b. b -> R a b
forall a b. b -> R a b
R @c Entity
target))
      ComponentRep
_ -> Query System c -> System (Maybe c)
forall w (m :: * -> *) out.
MonadSystem w m =>
Query m out -> m (Maybe out)
single (Entity -> C c -> Query System c
forall qd out (m :: * -> *).
Queryable qd out =>
Entity -> qd -> Query m out
mkGet Entity
entity (forall a. C a
forall {k} (a :: k). C a
C @c))

    case val' of
      Maybe c
Nothing -> Bool -> System Bool
forall a. a -> System a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
      Just c
val' -> Bool -> System Bool
forall a. a -> System a
forall (m :: * -> *) a. Monad m => a -> m a
return (c
val c -> c -> Bool
forall a. Eq a => a -> a -> Bool
/= c
val')

  resources <- flip filterM (Set.toList resources) $ \BundleElement {ComponentRep
rep :: forall e. BundleElement e -> ComponentRep
rep :: ComponentRep
rep, component :: forall e. BundleElement e -> e
component = ErasedComponentEq (c
val :: c)} -> do
    e <- forall c. Component c => System Entity
meta @c
    val' <- case rep of
      ComponentRep ComponentType
_ -> Query System c -> System (Maybe c)
forall w (m :: * -> *) out.
MonadSystem w m =>
Query m out -> m (Maybe out)
single (Query System c -> System (Maybe c))
-> Query System c -> System (Maybe c)
forall a b. (a -> b) -> a -> b
$ Entity -> C c -> Query System c
forall qd out (m :: * -> *).
Queryable qd out =>
Entity -> qd -> Query m out
mkGet Entity
e (forall a. C a
forall {k} (a :: k). C a
C @c)
      ComponentRep
_ -> System (Maybe c)
forall a. HasCallStack => a
undefined

    case val' of
      Maybe c
Nothing -> Bool -> System Bool
forall a. a -> System a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
      Just c
val' -> Bool -> System Bool
forall a. a -> System a
forall (m :: * -> *) a. Monad m => a -> m a
return (c
val c -> c -> Bool
forall a. Eq a => a -> a -> Bool
/= c
val')

  for_ external $ \(Entity
e, BundleData ErasedComponentEq
external) -> do
    BundleData ErasedComponentEq -> Entity -> System ()
forall b. BundleEq b => b -> Entity -> System ()
insertIfNeq BundleData ErasedComponentEq
external Entity
e
    System (ZonkAny 0)
forall a. HasCallStack => a
undefined

  insert (bundleEqToSimple $ BundleData (Set.fromList comps) (Set.fromList resources) Set.empty) entity

triggerAddEvent :: ProcessedBundleData -> Entity -> System ()
triggerAddEvent :: ProcessedBundleData -> Entity -> System ()
triggerAddEvent ProcessedBundleData
bundle Entity
entity =
  [ProcessedBundleElement]
-> (ProcessedBundleElement -> System ()) -> System ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ ProcessedBundleData
bundle.elements ((ProcessedBundleElement -> System ()) -> System ())
-> (ProcessedBundleElement -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \ProcessedBundleElement
x -> do
    let !(ComponentId (# Word#
_, Maybe Entity
target #)) = ProcessedBundleElement
x.id
    case Maybe Entity
target of
      Maybe Entity
Nothing ->
        ErasedComponent -> Entity -> System ()
triggerAddEventC ProcessedBundleElement
x.component.value Entity
entity
      Just Entity
target ->
        ErasedComponent -> Entity -> Entity -> System ()
triggerAddEventR ProcessedBundleElement
x.component.value Entity
target Entity
entity

triggerAddEventC :: ErasedComponent -> Entity -> System ()
triggerAddEventC :: ErasedComponent -> Entity -> System ()
triggerAddEventC (ErasedComponent (c
_ :: c)) Entity
entity = do
  let context :: HookContext
context = HookContext {Entity
entity :: Entity
entity :: Entity
entity}

  m <- forall c. Component c => System Entity
meta @c
  hooks <- single $ mkGet m (C @ComponentAddHooks)
  for_ hooks $ \(ComponentAddHooks [HookContext -> System ()]
h) -> do
    [HookContext -> System ()]
-> ((HookContext -> System ()) -> System ()) -> System ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [HookContext -> System ()]
h (((HookContext -> System ()) -> System ()) -> System ())
-> ((HookContext -> System ()) -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \HookContext -> System ()
h -> HookContext -> System ()
h HookContext
context

  runEvent $ eraseEvent $ OnAdd @c entity

triggerAddEventR :: ErasedComponent -> Entity -> Entity -> System ()
triggerAddEventR :: ErasedComponent -> Entity -> Entity -> System ()
triggerAddEventR (ErasedComponent (c
_ :: c)) Entity
target Entity
entity = do
  let context :: HookContextRel
context = HookContextRel {Entity
entity :: Entity
entity :: Entity
entity, Entity
target :: Entity
target :: Entity
target}

  m <- forall c. Component c => System Entity
meta @c
  Just hooks <- single $ mkGet m (M @ComponentAddHooksRel)
  for_ hooks $ \(ComponentAddHooksRel [HookContextRel -> System ()]
h) -> do
    [HookContextRel -> System ()]
-> ((HookContextRel -> System ()) -> System ()) -> System ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [HookContextRel -> System ()]
h (((HookContextRel -> System ()) -> System ()) -> System ())
-> ((HookContextRel -> System ()) -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \HookContextRel -> System ()
h -> HookContextRel -> System ()
h HookContextRel
context

  runEvent $ eraseEvent $ OnAddRel @c entity target

triggerSetEvent :: ProcessedBundleData -> Entity -> System ()
triggerSetEvent :: ProcessedBundleData -> Entity -> System ()
triggerSetEvent ProcessedBundleData
bundle Entity
entity =
  [ProcessedBundleElement]
-> (ProcessedBundleElement -> System ()) -> System ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ ProcessedBundleData
bundle.elements ((ProcessedBundleElement -> System ()) -> System ())
-> (ProcessedBundleElement -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \ProcessedBundleElement
x -> do
    let !(ComponentId (# Word#
_, Maybe Entity
target #)) = ProcessedBundleElement
x.id
    case Maybe Entity
target of
      Maybe Entity
Nothing ->
        ErasedComponent -> Entity -> System ()
triggerSetEventC ProcessedBundleElement
x.component.value Entity
entity
      Just Entity
target ->
        ErasedComponent -> Entity -> Entity -> System ()
triggerSetEventR ProcessedBundleElement
x.component.value Entity
target Entity
entity

triggerSetEventC :: ErasedComponent -> Entity -> System ()
triggerSetEventC :: ErasedComponent -> Entity -> System ()
triggerSetEventC (ErasedComponent (c
_ :: c)) Entity
entity = do
  let context :: HookContext
context = HookContext {Entity
entity :: Entity
entity :: Entity
entity}

  m <- forall c. Component c => System Entity
meta @c
  Just hooks <- single $ mkGet m (M @ComponentSetHooks)
  for_ hooks $ \(ComponentSetHooks [HookContext -> System ()]
h) -> do
    [HookContext -> System ()]
-> ((HookContext -> System ()) -> System ()) -> System ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [HookContext -> System ()]
h (((HookContext -> System ()) -> System ()) -> System ())
-> ((HookContext -> System ()) -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \HookContext -> System ()
h -> HookContext -> System ()
h HookContext
context

  runEvent $ eraseEvent $ OnSet @c entity

triggerSetEventR :: ErasedComponent -> Entity -> Entity -> System ()
triggerSetEventR :: ErasedComponent -> Entity -> Entity -> System ()
triggerSetEventR (ErasedComponent (c
_ :: c)) Entity
target Entity
entity = do
  let context :: HookContextRel
context = HookContextRel {Entity
entity :: Entity
entity :: Entity
entity, Entity
target :: Entity
target :: Entity
target}

  m <- forall c. Component c => System Entity
meta @c
  Just hooks <- single $ mkGet m (M @ComponentSetHooksRel)
  for_ hooks $ \(ComponentSetHooksRel [HookContextRel -> System ()]
h) -> do
    [HookContextRel -> System ()]
-> ((HookContextRel -> System ()) -> System ()) -> System ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [HookContextRel -> System ()]
h (((HookContextRel -> System ()) -> System ()) -> System ())
-> ((HookContextRel -> System ()) -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \HookContextRel -> System ()
h -> HookContextRel -> System ()
h HookContextRel
context

  runEvent $ eraseEvent $ OnSetRel @c entity target