diff options
Diffstat (limited to 'composeApp/src/commonMain/kotlin/coffee/liz/ecs/DAGWorld.kt')
| -rw-r--r-- | composeApp/src/commonMain/kotlin/coffee/liz/ecs/DAGWorld.kt | 61 |
1 files changed, 24 insertions, 37 deletions
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/ecs/DAGWorld.kt b/composeApp/src/commonMain/kotlin/coffee/liz/ecs/DAGWorld.kt index d314065..77cb30b 100644 --- a/composeApp/src/commonMain/kotlin/coffee/liz/ecs/DAGWorld.kt +++ b/composeApp/src/commonMain/kotlin/coffee/liz/ecs/DAGWorld.kt @@ -1,28 +1,27 @@ package coffee.liz.ecs +import kotlin.concurrent.atomics.AtomicInt +import kotlin.concurrent.atomics.ExperimentalAtomicApi +import kotlin.concurrent.atomics.incrementAndFetch import kotlin.reflect.KClass +import kotlin.time.Duration /** - * World implementation that executes systems in dependency order using a DAG. + * [World] that updates in [System.dependencies] DAG order. */ -class DAGWorld(systems: List<System>) : World { +@OptIn(ExperimentalAtomicApi::class) +class DAGWorld<Outside>(systems: List<System<Outside>>) : World<Outside> { private val entities = mutableSetOf<Entity>() private val componentCache = mutableMapOf<KClass<out Component>, MutableSet<Entity>>() - private val systemExecutionOrder: List<System> - private var nextEntityId = 0 - - init { - systemExecutionOrder = buildExecutionOrder(systems) - } + private val systemExecutionOrder: List<System<Outside>> = buildExecutionOrder(systems) + private val nextEntityId = AtomicInt(0) override fun createEntity(): Entity { - val entity = Entity(nextEntityId++) - entities.add(entity) - return entity + return Entity(nextEntityId.incrementAndFetch()) + .also { entities.add(it) } } - override fun destroyEntity(entity: Entity) { - // Remove from all component caches + override fun removeEntity(entity: Entity) { entity.componentTypes().forEach { componentType -> componentCache[componentType]?.remove(entity) } @@ -38,25 +37,18 @@ class DAGWorld(systems: List<System>) : World { // Filter to entities that have all component types return candidates.filter { entity -> - entity.hasAll(*componentTypes) + componentTypes.all { entity.has(it) } }.toSet() } - override fun update(deltaTime: Float) { - // Update component cache based on current entity state - updateComponentCache() - - // Execute systems in dependency order + override fun update(state: Outside, deltaTime: Duration) { + refreshComponentCache() systemExecutionOrder.forEach { system -> - system.update(this, deltaTime) + system.update(this, state, deltaTime) } } - /** - * Rebuild the component cache based on current entity components. - * Call this after components have been added/removed from entities. - */ - private fun updateComponentCache() { + private fun refreshComponentCache() { componentCache.clear() entities.forEach { entity -> entity.componentTypes().forEach { componentType -> @@ -67,14 +59,13 @@ class DAGWorld(systems: List<System>) : World { /** * Build a topologically sorted execution order from system dependencies. - * Uses Kahn's algorithm for topological sorting. */ - private fun buildExecutionOrder(systems: List<System>): List<System> { + private fun buildExecutionOrder(systems: List<System<Outside>>): List<System<Outside>> { if (systems.isEmpty()) return emptyList() val systemMap = systems.associateBy { it::class } - val inDegree = mutableMapOf<KClass<out System>, Int>() - val adjacencyList = mutableMapOf<KClass<out System>, MutableSet<KClass<out System>>>() + val inDegree = mutableMapOf<KClass<out System<Outside>>, Int>() + val adjacencyList = mutableMapOf<KClass<out System<Outside>>, MutableSet<KClass<out System<Outside>>>>() // Initialize graph systems.forEach { system -> @@ -94,15 +85,11 @@ class DAGWorld(systems: List<System>) : World { } // Kahn's algorithm - val queue = ArrayDeque<KClass<out System>>() - val result = mutableListOf<System>() + val queue = ArrayDeque<KClass<out System<Outside>>>() + val result = mutableListOf<System<Outside>>() // Add all systems with no dependencies to queue - inDegree.forEach { (systemClass, degree) -> - if (degree == 0) { - queue.add(systemClass) - } - } + queue.addAll(inDegree.filterValues { it == 0 }.keys) while (queue.isNotEmpty()) { val currentClass = queue.removeFirst() @@ -119,7 +106,7 @@ class DAGWorld(systems: List<System>) : World { // Check for cycles if (result.size != systems.size) { - throw IllegalArgumentException("Circular dependency detected in systems") + error("Circular dependency detected in systems") } return result |
