module Mischief.ECS.World.Change where import Control.Monad.Reader (MonadIO (liftIO), ask) import Data.Foldable import Data.IORef import Data.Map qualified as Map import Data.Maybe import Data.Set qualified as Set import GHC.Base (Int (..)) import GHC.Stack (HasCallStack) import Mischief.ECS.App.SystemDef import Mischief.ECS.Archetypes import Mischief.ECS.Components import Mischief.ECS.Components.Bundle import Mischief.ECS.Entities import Mischief.ECS.EntityDef 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.Query import Mischief.ECS.World.Query.Queryable import Mischief.ECS.World.Utils data ChangeResult = ChangeResult { ChangeResult -> [ProcessedBundleElement] requiredComponentsAdded :: [ProcessedBundleElement], ChangeResult -> [ProcessedBundleElement] newComponents :: [ProcessedBundleElement] } changeArchetype :: (HasCallStack) => Entity -> ArchetypeData -> Maybe ProcessedBundleData -> System ChangeResult changeArchetype :: HasCallStack => Entity -> ArchetypeData -> Maybe ProcessedBundleData -> System ChangeResult changeArchetype Entity entity ArchetypeData newArchetype Maybe ProcessedBundleData insertedBundle = do world <- System World forall w (m :: * -> *). MonadSystem w m => m World unsafeGetWorld currentTick <- liftIO $ readIORef world.tick reqAdded <- liftIO $ newIORef [] Just pointer <- liftIO $ getPointer entity world.entities (EntityPointer (# archetypeId', rowIndex' #)) <- liftIO $ readIORef pointer table <- Vec.read world.tables.inner (I# archetypeId') collected <- liftIO $ takeComponentsFromTable (EntityPointer (# archetypeId', rowIndex' #)) table newElements'' <- mapM ( \ComponentId component -> do case Maybe ProcessedBundleData insertedBundle of Maybe ProcessedBundleData Nothing -> System ProcessedBundleElement -> (ProcessedBundleElement -> System ProcessedBundleElement) -> Maybe ProcessedBundleElement -> System ProcessedBundleElement forall b a. b -> (a -> b) -> Maybe a -> b maybe System ProcessedBundleElement forall a. HasCallStack => a undefined ProcessedBundleElement -> System ProcessedBundleElement forall a. a -> System a forall (m :: * -> *) a. Monad m => a -> m a return ((ProcessedBundleElement -> Bool) -> [ProcessedBundleElement] -> Maybe ProcessedBundleElement forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a find (\ProcessedBundleElement x -> ProcessedBundleElement x.id ComponentId -> ComponentId -> Bool forall a. Eq a => a -> a -> Bool == ComponentId component) ProcessedBundleData collected.elements) Just ProcessedBundleData bundle -> case (ProcessedBundleElement -> Bool) -> [ProcessedBundleElement] -> Maybe ProcessedBundleElement forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a find (\ProcessedBundleElement x -> ProcessedBundleElement x.id ComponentId -> ComponentId -> Bool forall a. Eq a => a -> a -> Bool == ComponentId component) ProcessedBundleData bundle.elements of Just ProcessedBundleElement x -> ProcessedBundleElement -> System ProcessedBundleElement forall a. a -> System a forall (m :: * -> *) a. Monad m => a -> m a return ProcessedBundleElement x Maybe ProcessedBundleElement Nothing -> case (ProcessedBundleElement -> Bool) -> [ProcessedBundleElement] -> Maybe ProcessedBundleElement forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a find (\ProcessedBundleElement x -> ProcessedBundleElement x.id ComponentId -> ComponentId -> Bool forall a. Eq a => a -> a -> Bool == ComponentId component) ProcessedBundleData collected.elements of Just ProcessedBundleElement x -> ProcessedBundleElement -> System ProcessedBundleElement forall a. a -> System a forall (m :: * -> *) a. Monad m => a -> m a return ProcessedBundleElement x Maybe ProcessedBundleElement Nothing -> do r <- ComponentId -> System ProcessedBundleElement getDefault ComponentId component liftIO $ modifyIORef' reqAdded (++ [r]) return r ) $ Set.toList newArchetype.components let newElements = case Maybe ProcessedBundleData insertedBundle of Maybe ProcessedBundleData Nothing -> [ProcessedBundleElement] -> ProcessedBundleData ProcessedBundleData [ProcessedBundleElement] newElements'' Just ProcessedBundleData bundle -> let newElements' :: ProcessedBundleData newElements' = ProcessedBundleData -> (ComponentId -> Bool) -> Tick -> ProcessedBundleData setChangedTickOfComponents ([ProcessedBundleElement] -> ProcessedBundleData ProcessedBundleData [ProcessedBundleElement] newElements'') (\ComponentId id -> ProcessedBundleData -> ComponentId -> Bool isInProcessedBundle ProcessedBundleData bundle ComponentId id Bool -> Bool -> Bool && ProcessedBundleData -> ComponentId -> Bool isInProcessedBundle ProcessedBundleData collected ComponentId id) Tick currentTick in ProcessedBundleData -> (ComponentId -> Bool) -> Tick -> ProcessedBundleData setAddedTickOfComponents ProcessedBundleData newElements' (\ComponentId id -> ProcessedBundleData -> ComponentId -> Bool isInProcessedBundle ProcessedBundleData bundle ComponentId id Bool -> Bool -> Bool && Bool -> Bool not (ProcessedBundleData -> ComponentId -> Bool isInProcessedBundle ProcessedBundleData collected ComponentId id)) Tick currentTick liftIO $ insertEntityIntoTables newElements world.tables newArchetype.id (entity, pointer) requiredComponentsAdded <- liftIO $ readIORef reqAdded return ChangeResult {requiredComponentsAdded} getDefault :: ComponentId -> System ProcessedBundleElement getDefault :: ComponentId -> System ProcessedBundleElement getDefault (ComponentId (# Word# id, Maybe Entity e #)) = do world <- System World forall w (m :: * -> *). MonadSystem w m => m World unsafeGetWorld Just x <- get (C @DefaultValue) (Entity (# id, 0## #)) let dv = Result DefaultValue -> DefaultValue forall c. Result c -> c value Result DefaultValue x let (DefaultValue value) = dv let (SystemId sys) = world.systemId currentSystemTick <- fromMaybe (SystemTick $ Tick (0, 0)) <$> get (Val $ C @SystemTick) sys return ProcessedBundleElement { id = ComponentId (# id, e #), component = ComponentData { value, ticks = ComponentTicks {changed = currentSystemTick.inner, added = currentSystemTick.inner} } }