summaryrefslogtreecommitdiff
path: root/composeApp/src/commonMain/kotlin/coffee/liz/ecs/DAGWorld.kt
diff options
context:
space:
mode:
Diffstat (limited to 'composeApp/src/commonMain/kotlin/coffee/liz/ecs/DAGWorld.kt')
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/ecs/DAGWorld.kt61
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