From afa9ab668bddbfbfe3e401c4bb9079e75aaec390 Mon Sep 17 00:00:00 2001 From: stillya Date: Sun, 24 May 2026 00:54:07 +0500 Subject: [PATCH] refactor: rid off from mutable entity id in pet --- .../dev/stillya/vpet/animation/Planner.kt | 6 -- .../dev/stillya/vpet/game/GameController.kt | 6 +- .../stillya/vpet/game/ecs/EntityRegistry.kt | 5 + .../dev/stillya/vpet/pet/PetAnimated.kt | 8 +- .../vpet/pet/PetAnimatedGameLifecycleTest.kt | 92 ------------------- .../vpet/pet/PetAnimatedIntegrationTest.kt | 21 ----- 6 files changed, 7 insertions(+), 131 deletions(-) delete mode 100644 src/test/kotlin/dev/stillya/vpet/pet/PetAnimatedGameLifecycleTest.kt diff --git a/src/main/kotlin/dev/stillya/vpet/animation/Planner.kt b/src/main/kotlin/dev/stillya/vpet/animation/Planner.kt index c9bb85a..b702fba 100644 --- a/src/main/kotlin/dev/stillya/vpet/animation/Planner.kt +++ b/src/main/kotlin/dev/stillya/vpet/animation/Planner.kt @@ -26,12 +26,6 @@ class GreedyPlanner( bridges: List ): PlanResult { log.trace("Planning from effect: $currentEffect to requirement: $requirement") - - if (requirement.isSatisfiedBy(currentEffect)) { - log.trace("Current effect already satisfies requirement") - return PlanResult(emptyList(), currentEffect) - } - val selectedBridges = mutableListOf() var effect = currentEffect diff --git a/src/main/kotlin/dev/stillya/vpet/game/GameController.kt b/src/main/kotlin/dev/stillya/vpet/game/GameController.kt index 61c6ebc..68e69ae 100644 --- a/src/main/kotlin/dev/stillya/vpet/game/GameController.kt +++ b/src/main/kotlin/dev/stillya/vpet/game/GameController.kt @@ -117,7 +117,7 @@ class GameController(private val project: Project) { val visualCol = mapper.toVisualColF(caretPixelX) val registry = EntityRegistry() - val player = registry.create() + val player = registry.register(character.id()) registry.add(player, Transform(visualCol, firstVisibleLine.toFloat())) registry.add(player, Velocity(0f, 0f)) registry.add(player, PhysicsState(isOnGround = false)) @@ -125,10 +125,6 @@ class GameController(private val project: Project) { registry.add(player, PhaseState(GamePhase.ENTRANCE)) registry.add(player, AABB(2, 2)) - if (character is dev.stillya.vpet.pet.PetAnimated) { - character.setEntityId(player) - } - return World(registry = registry, player = player) } } diff --git a/src/main/kotlin/dev/stillya/vpet/game/ecs/EntityRegistry.kt b/src/main/kotlin/dev/stillya/vpet/game/ecs/EntityRegistry.kt index 8f07e9e..6927cfa 100644 --- a/src/main/kotlin/dev/stillya/vpet/game/ecs/EntityRegistry.kt +++ b/src/main/kotlin/dev/stillya/vpet/game/ecs/EntityRegistry.kt @@ -14,6 +14,11 @@ class EntityRegistry { return id } + fun register(id: EntityID): EntityID { + components[id] = mutableMapOf() + return id + } + fun destroy(id: EntityID) { components.remove(id) pendingRemovals.remove(id) diff --git a/src/main/kotlin/dev/stillya/vpet/pet/PetAnimated.kt b/src/main/kotlin/dev/stillya/vpet/pet/PetAnimated.kt index ebb73f4..5cb5638 100644 --- a/src/main/kotlin/dev/stillya/vpet/pet/PetAnimated.kt +++ b/src/main/kotlin/dev/stillya/vpet/pet/PetAnimated.kt @@ -37,8 +37,6 @@ class PetAnimated( private val renderer: IconRenderer get() = project.service() - private var entityId: EntityID? = null - var random: Random = Random set(value) { field = value @@ -292,11 +290,7 @@ class PetAnimated( playTransition(pivotSequence to AnimationState.OBSERVING, context) } - override fun id() = entityId ?: error("EntityID not initialized - call setEntityId first") - - fun setEntityId(id: EntityID) { - entityId = id - } + override fun id() = EntityID("pet") override fun collider() = AABB(width = 2, height = 2) diff --git a/src/test/kotlin/dev/stillya/vpet/pet/PetAnimatedGameLifecycleTest.kt b/src/test/kotlin/dev/stillya/vpet/pet/PetAnimatedGameLifecycleTest.kt deleted file mode 100644 index 47f7aac..0000000 --- a/src/test/kotlin/dev/stillya/vpet/pet/PetAnimatedGameLifecycleTest.kt +++ /dev/null @@ -1,92 +0,0 @@ -package dev.stillya.vpet.pet - -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.components.service -import com.intellij.testFramework.LightPlatform4TestCase -import com.intellij.testFramework.registerServiceInstance -import dev.stillya.vpet.Animated -import dev.stillya.vpet.AtlasLoader -import dev.stillya.vpet.IconRenderer -import dev.stillya.vpet.config.AsepriteJsonAtlasLoader -import dev.stillya.vpet.game.Character -import dev.stillya.vpet.game.Game -import dev.stillya.vpet.game.ecs.EntityID -import org.junit.Test - -class PetAnimatedGameLifecycleTest : LightPlatform4TestCase() { - - private lateinit var petAnimated: PetAnimated - - override fun setUp() { - super.setUp() - - ApplicationManager.getApplication() - .registerServiceInstance(AtlasLoader::class.java, AsepriteJsonAtlasLoader()) - project.registerServiceInstance(IconRenderer::class.java, IconRendererSpy(project)) - project.registerServiceInstance(Animated::class.java, PetAnimated(project)) - - petAnimated = project.service() as PetAnimated - petAnimated.init( - Animated.Params( - atlasPath = "/META-INF/spritesheets/cat/atlas.json", - imgPath = "/META-INF/spritesheets/cat/sprite.png" - ) - ) - } - - @Test - fun `PetAnimated implements all three interfaces`() { - val animated: Animated = project.service() - assertTrue("PetAnimated should implement Character", animated is Character) - assertTrue("PetAnimated should implement Game", animated is Game) - } - - @Test - fun `onGameStart does not throw and state is consistent`() { - val game = petAnimated as Game - game.onGameStart() - // No exception means state is consistent - } - - @Test - fun `onGameStop does not throw and state is consistent`() { - val game = petAnimated as Game - game.onGameStop() - // No exception means state is consistent - } - - @Test - fun `onGameStart followed by onGameStop leaves pet in consistent state`() { - val game = petAnimated as Game - game.onGameStart() - game.onGameStop() - // No exception means state is consistent - } - - @Test - fun `multiple start-stop cycles do not break the pet`() { - val game = petAnimated as Game - repeat(3) { - game.onGameStart() - game.onGameStop() - } - // No exception — state is consistent - } - - @Test - fun `Animated service can be cast to Game for lifecycle wiring`() { - val animated = project.service() - // This is exactly what GameController does — ensure it doesn't throw - val game = animated as Game - game.onGameStart() - game.onGameStop() - } - - @Test - fun `PetAnimated exposes stable spatial id`() { - val character = project.service() as Character - val testId = EntityID("test_player") - (character as PetAnimated).setEntityId(testId) - assertEquals(testId, character.id()) - } -} diff --git a/src/test/kotlin/dev/stillya/vpet/pet/PetAnimatedIntegrationTest.kt b/src/test/kotlin/dev/stillya/vpet/pet/PetAnimatedIntegrationTest.kt index 8f61844..7bdf8b6 100644 --- a/src/test/kotlin/dev/stillya/vpet/pet/PetAnimatedIntegrationTest.kt +++ b/src/test/kotlin/dev/stillya/vpet/pet/PetAnimatedIntegrationTest.kt @@ -10,7 +10,6 @@ import dev.stillya.vpet.AtlasLoader import dev.stillya.vpet.IconRenderer import dev.stillya.vpet.animation.Animation import dev.stillya.vpet.config.AsepriteJsonAtlasLoader -import dev.stillya.vpet.game.ecs.EntityID import dev.stillya.vpet.graphics.AnimationContext import dev.stillya.vpet.graphics.AnimationEpochManager import dev.stillya.vpet.graphics.AnimationTrigger @@ -193,7 +192,6 @@ class PetAnimatedIntegrationTest : LightPlatform4TestCase() { rendererSpy.clear() petAnimated.onProgress() - val runningAnimationCount = rendererSpy.enqueuedAnimations.size petAnimated.onFail() val afterFailCount = rendererSpy.enqueuedAnimations.size @@ -278,25 +276,6 @@ class PetAnimatedIntegrationTest : LightPlatform4TestCase() { assertTrue("Should flip when cursor moves to different sides", flippedLeft || flippedRight) } - - @Test - fun testEntityIdCanBeSetAndRetrieved() { - val newId = EntityID("player_123") - petAnimated.setEntityId(newId) - - assertEquals("EntityID should be updated after setEntityId call", newId, petAnimated.id()) - } - - @Test - fun testEntityIdRequiresInitialization() { - val freshPet = PetAnimated(project) - try { - freshPet.id() - fail("Expected IllegalStateException when accessing uninitialized EntityID") - } catch (e: IllegalStateException) { - assertTrue("Error message should mention initialization", e.message?.contains("not initialized") == true) - } - } } class IconRendererSpy(project: Project) : IconRenderer {