From 6942fa32c9bf6a08bbfb4d4169f4d4afce6c3849 Mon Sep 17 00:00:00 2001 From: 0ffz Date: Sat, 22 Jan 2022 02:23:31 -0500 Subject: [PATCH 1/6] Start web console module --- build.gradle.kts | 16 +---- .../geary.kotlin-conventions.gradle.kts | 8 --- geary-core/build.gradle.kts | 9 ++- .../mineinabyss/geary/ecs/api/GearyType.kt | 6 ++ .../geary/ecs/api/systems/QueryManager.kt | 4 +- .../mineinabyss/geary/ecs/engine/Archetype.kt | 37 +++++----- .../geary/ecs/engine/ArchetypeIterator.kt | 2 +- .../geary/ecs/engine/GearyEngine.kt | 7 +- .../mineinabyss/geary/ecs/engine/TypeMap.kt | 6 +- geary-prefabs/build.gradle.kts | 6 +- geary-web-console/build.gradle.kts | 67 +++++++++++++++++++ .../geary/webconsole/GearyWebConsole.kt | 28 ++++++++ .../geary-platform-papermc/build.gradle.kts | 6 +- .../geary/minecraft/GearyPlugin.kt | 3 + .../geary/minecraft/config/GearyConfig.kt | 24 ++++++- settings.gradle.kts | 22 ++++++ 16 files changed, 192 insertions(+), 59 deletions(-) create mode 100644 geary-web-console/build.gradle.kts create mode 100644 geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt diff --git a/build.gradle.kts b/build.gradle.kts index ff899ceea..4365c397d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,20 +1,8 @@ -import Com_mineinabyss_conventions_platform_gradle.Deps - plugins { java - kotlin("jvm") - id("org.jetbrains.dokka") - id("com.mineinabyss.conventions.platform") +// kotlin("multiplatform") +// id("org.jetbrains.dokka") } - -repositories { - mavenCentral() -} - -dependencies { - compileOnly(Deps.kotlin.stdlib) -} - tasks { build { dependsOn(project(":geary-platform-papermc").tasks.build) diff --git a/geary-conventions/src/main/kotlin/geary.kotlin-conventions.gradle.kts b/geary-conventions/src/main/kotlin/geary.kotlin-conventions.gradle.kts index 64c4180ef..5ce845fed 100644 --- a/geary-conventions/src/main/kotlin/geary.kotlin-conventions.gradle.kts +++ b/geary-conventions/src/main/kotlin/geary.kotlin-conventions.gradle.kts @@ -12,14 +12,6 @@ repositories { mavenCentral() } -object GearyDeps { - val bimap = "com.uchuhimo:kotlinx-bimap:1.2" - val bitvector = "net.onedaybeard.bitvector:bitvector-jvm:0.1.4" - val fastutil = "it.unimi.dsi:fastutil:8.2.2" //Version on minecraft server - val reflections = "org.reflections:reflections:0.9.12" - val plugman = "com.rylinaux:PlugMan:2.2.5" -} - dependencies { // MineInAbyss platform compileOnly(Deps.kotlin.stdlib) diff --git a/geary-core/build.gradle.kts b/geary-core/build.gradle.kts index 602cb045c..439fa1d15 100644 --- a/geary-core/build.gradle.kts +++ b/geary-core/build.gradle.kts @@ -1,5 +1,4 @@ import Com_mineinabyss_conventions_platform_gradle.Deps -import Geary_kotlin_conventions_gradle.GearyDeps plugins { id("geary.kotlin-conventions") @@ -10,12 +9,12 @@ plugins { dependencies { //ecs-related libs - implementation(GearyDeps.bimap) { isTransitive = false } - implementation(GearyDeps.bitvector) + implementation(gearylibs.bimap) { isTransitive = false } + implementation(gearylibs.bitvector) implementation(Deps.kotlin.reflect) { isTransitive = false } //provided by Minecraft // TODO implementation here, avoid shading on papermc - compileOnly(GearyDeps.fastutil) - testImplementation(GearyDeps.fastutil) + compileOnly(gearylibs.fastutil) + testImplementation(gearylibs.fastutil) } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/GearyType.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/GearyType.kt index 6c1f2c4b2..f4c8a0fc4 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/GearyType.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/GearyType.kt @@ -1,8 +1,10 @@ package com.mineinabyss.geary.ecs.api +import com.mineinabyss.geary.ecs.api.engine.getComponentInfo import it.unimi.dsi.fastutil.longs.LongAVLTreeSet import it.unimi.dsi.fastutil.longs.LongSortedSet import it.unimi.dsi.fastutil.longs.LongSortedSets +import kotlin.reflect.KClass /** * An inlined class used for tracking the components an entity/archetype has. @@ -58,4 +60,8 @@ public value class GearyType private constructor( public operator fun minus(id: GearyComponentId): GearyType = GearyType(LongAVLTreeSet(inner).apply { remove(id.toLong()) }) + + override fun toString(): String = inner + .map { (it.toULong().getComponentInfo()?.kClass as KClass<*>).simpleName ?: it } + .joinToString { ", " } } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt index cb7cb544f..9384aecec 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt @@ -55,7 +55,9 @@ public object QueryManager { if (arrIndex != -1) argArray[arrIndex] = args[i] } kFunction.isAccessible = true - return kFunction.call(*argArray) + return runCatching { kFunction.call(*argArray) } + // Don't print the whole reflection error, just the cause + .getOrElse { throw it.cause ?: it } } } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt index 4347f8c58..ba75df254 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt @@ -16,7 +16,6 @@ import com.mineinabyss.geary.ecs.query.Query import com.mineinabyss.geary.ecs.query.contains import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap -import it.unimi.dsi.fastutil.longs.LongArrayList import java.util.* /** @@ -32,7 +31,7 @@ public data class Archetype( ) { /** The entity ids in this archetype. Indices are the same as [componentData]'s sub-lists. */ //TODO aim to make private - internal val ids: LongArrayList = LongArrayList() + internal val ids = mutableListOf() /** Component ids in the type that are to hold data */ // Currently all relations must hold data and the HOLDS_DATA bit on them corresponds to the component part. @@ -124,7 +123,7 @@ public data class Archetype( } /** @return The entity stored at a given [row] in this archetype. */ - internal fun getEntity(row: Int): GearyEntity = ids.getLong(row).toGeary() + internal fun getEntity(row: Int): GearyEntity = ids.get(row).toGeary() /** @return Whether this archetype has a [componentId] in its type, regardless of the [HOLDS_DATA] role. */ public operator fun contains(componentId: GearyComponentId): Boolean = @@ -279,21 +278,25 @@ public data class Archetype( /** Removes the entity at a [row] in this archetype, notifying running archetype iterators. */ @Synchronized internal fun removeEntity(row: Int) { - val replacement = ids.last() - val lastIndex = ids.lastIndex - ids[row] = replacement - - if (lastIndex != row) - componentData.forEach { it[row] = it.last() } - - ids.removeLastOrNull() - componentData.forEach { it.removeLastOrNull() } - - if (lastIndex != row) { - runningIterators.forEach { - it.addMovedRow(lastIndex, row) + try { + val lastIndex = ids.lastIndex + val replacement = ids.get(lastIndex) + ids[row] = replacement + + if (lastIndex != row) + componentData.forEach { it[row] = it.last() } + + ids.removeLastOrNull() + componentData.forEach { it.removeLastOrNull() } + + if (lastIndex != row) { + runningIterators.forEach { + it.addMovedRow(lastIndex, row) + } + Engine.setRecord(replacement.toGeary(), Record.of(this, row)) } - Engine.setRecord(replacement.toGeary(), Record.of(this, row)) + } catch (e: IndexOutOfBoundsException) { + throw IllegalStateException("Error while removing entity at row $row for archetype $this", e) } } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/ArchetypeIterator.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/ArchetypeIterator.kt index 58ff58fc1..ae0d80c85 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/ArchetypeIterator.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/ArchetypeIterator.kt @@ -32,7 +32,7 @@ public data class ArchetypeIterator( if (combinationsIterator?.hasNext() != true) { val destinationRow = movedRows.firstOrNull() ?: row++ movedRows.remove(destinationRow) - val entity = archetype.ids.getLong( destinationRow).toGeary() + val entity = archetype.ids.get( destinationRow).toGeary() combinationsIterator = holder.iteratorFor( RawAccessorDataScope( diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt index 382d471f8..8964c05cd 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt @@ -197,7 +197,10 @@ public open class GearyEngine : TickingEngine() { } } - clearEntity(entity) + getRecord(entity).apply { + archetype.removeEntity(row) + } + typeMap.remove(entity) //add current id into queue for reuse removedEntities.push(entity) @@ -207,7 +210,7 @@ public open class GearyEngine : TickingEngine() { getRecord(entity).apply { archetype.removeEntity(row) } - typeMap.remove(entity) + typeMap[entity] = rootArchetype.addEntityWithData(entity, listOf()) } override fun getArchetype(id: Int): Archetype = archetypes[id] diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TypeMap.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TypeMap.kt index 8738ca6f3..584981669 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TypeMap.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TypeMap.kt @@ -5,14 +5,14 @@ import it.unimi.dsi.fastutil.longs.Long2LongMap import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap @JvmInline -public value class TypeMap(public val map: Long2LongMap = Long2LongOpenHashMap()) { +public value class TypeMap(public val map: MutableMap = mutableMapOf()/*: Long2LongMap = Long2LongOpenHashMap()*/) { public operator fun contains(entity: GearyEntity): Boolean = map.contains(entity.id.toLong()) // We don't return nullable record to avoid boxing. // Accessing an entity that doesn't exist is indicative of a problem elsewhere and should be made obvious. public operator fun get(entity: GearyEntity): Record { - val id = map[entity.id.toLong()] - if (id == -1L) error("Tried to access components on an entity that no longer exists (${entity.id})") + val id = map[entity.id.toLong()] ?: + /*if (id == -1L) */error("Tried to access components on an entity that no longer exists (${entity.id})") return Record(id) } diff --git a/geary-prefabs/build.gradle.kts b/geary-prefabs/build.gradle.kts index e35844522..de17005c3 100644 --- a/geary-prefabs/build.gradle.kts +++ b/geary-prefabs/build.gradle.kts @@ -1,5 +1,3 @@ -import Geary_kotlin_conventions_gradle.GearyDeps - plugins { id("geary.kotlin-conventions") kotlin("plugin.serialization") @@ -8,8 +6,8 @@ plugins { } dependencies { - compileOnly(GearyDeps.bimap) { isTransitive = false } - compileOnly(GearyDeps.fastutil) + compileOnly(gearylibs.bimap) { isTransitive = false } + compileOnly(gearylibs.fastutil) compileOnly(project(":geary-core")) } diff --git a/geary-web-console/build.gradle.kts b/geary-web-console/build.gradle.kts new file mode 100644 index 000000000..424a4b79c --- /dev/null +++ b/geary-web-console/build.gradle.kts @@ -0,0 +1,67 @@ +import Com_mineinabyss_conventions_platform_gradle.Deps + +plugins { + java + kotlin("multiplatform") + kotlin("plugin.serialization") + id("com.mineinabyss.conventions.platform") +// id("com.mineinabyss.conventions.publication") +// id("com.mineinabyss.conventions.testing") +} + +repositories { + mavenCentral() +} + +kotlin { + jvm { + withJava() + } + js { + browser { + binaries.executable() + } + } + + sourceSets { + //TODO potentially version catalogs will help since we can't use platforms here AFAIK + val commonMain by getting { + dependencies { + compileOnly(libs.kotlin.stdlib) + compileOnly(libs.kotlinx.serialization.json) + compileOnly(libs.ktor.client.core) + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + } + } + + val jvmMain by getting { + dependencies { + compileOnly(project(":geary-core")) + compileOnly(libs.kotlin.stdlib) + compileOnly(libs.ktor.serialization) + compileOnly(libs.ktor.server.core) + compileOnly(libs.ktor.server.netty) + compileOnly(libs.logback.classic) + compileOnly(libs.kmongo.coroutine.serialization) + } + } + + val jsMain by getting { + dependencies { + implementation(libs.ktor.client.js) + implementation(libs.ktor.client.json) + implementation(libs.ktor.client.serialization) + } + } + } +} + +tasks.named("jvmProcessResources") { + val jsBrowserDistribution = tasks.named("jsBrowserDistribution") + from(jsBrowserDistribution) +} diff --git a/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt b/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt new file mode 100644 index 000000000..3958f7821 --- /dev/null +++ b/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt @@ -0,0 +1,28 @@ +package com.mineinabyss.geary.webconsole + +import io.ktor.application.* +import io.ktor.response.* +import io.ktor.routing.* +import io.ktor.server.engine.* +import io.ktor.server.netty.* + +class GearyWebConsole( + val port: Int = 9090, + val host: String = "0.0.0.0", +) { + private var runningServer: NettyApplicationEngine? = null + + fun start() { + runningServer = embeddedServer(Netty, port = port, host = host) { + routing { + get("/hello") { + call.respondText("Hello world") + } + } + }.start(wait = false) + } + + fun stop() { + runningServer?.stop(1000, 2000) + } +} diff --git a/platforms/geary-platform-papermc/build.gradle.kts b/platforms/geary-platform-papermc/build.gradle.kts index 813e8c44d..a3ef660a0 100644 --- a/platforms/geary-platform-papermc/build.gradle.kts +++ b/platforms/geary-platform-papermc/build.gradle.kts @@ -1,5 +1,4 @@ import Com_mineinabyss_conventions_platform_gradle.Deps -import Geary_kotlin_conventions_gradle.GearyDeps plugins { id("geary.kotlin-conventions") @@ -21,14 +20,15 @@ dependencies { compileOnly(Deps.kotlin.reflect) { isTransitive = false } // Other plugins - compileOnly(GearyDeps.plugman) + compileOnly(gearylibs.plugman) // Shaded api(project(":geary-core")) { exclude(module = "kotlin-reflect") } api(project(":geary-prefabs")) - implementation(GearyDeps.reflections) + implementation(project(":geary-web-console")) + implementation(gearylibs.reflections) } tasks { diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt index 8fac0b525..7c1499db3 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt @@ -8,6 +8,7 @@ import com.mineinabyss.geary.ecs.serialization.withSerialName import com.mineinabyss.geary.minecraft.access.BukkitAssociations import com.mineinabyss.geary.minecraft.access.BukkitEntityAssociations import com.mineinabyss.geary.minecraft.access.toGeary +import com.mineinabyss.geary.minecraft.config.GearyConfig import com.mineinabyss.geary.minecraft.dsl.GearyLoadPhase import com.mineinabyss.geary.minecraft.dsl.gearyAddon import com.mineinabyss.geary.minecraft.engine.SpigotEngine @@ -15,6 +16,7 @@ import com.mineinabyss.geary.minecraft.listeners.GearyAttemptSpawnListener import com.mineinabyss.geary.minecraft.listeners.InheritPrefabsOnLoad import com.mineinabyss.geary.minecraft.store.FileSystemStore import com.mineinabyss.geary.minecraft.store.GearyStore +import com.mineinabyss.geary.webconsole.GearyWebConsole import com.mineinabyss.idofront.platforms.IdofrontPlatforms import com.mineinabyss.idofront.plugin.registerEvents import com.mineinabyss.idofront.plugin.registerService @@ -38,6 +40,7 @@ public class GearyPlugin : JavaPlugin() { saveDefaultConfig() reloadConfig() + GearyConfig.load() GearyServices.setServiceProvider(object : GearyServiceProvider { override fun getService(service: KClass): T? { return Bukkit.getServer().servicesManager.load(service.java) diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/config/GearyConfig.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/config/GearyConfig.kt index 7e5e8dd84..a293428ce 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/config/GearyConfig.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/config/GearyConfig.kt @@ -1,12 +1,34 @@ package com.mineinabyss.geary.minecraft.config import com.mineinabyss.geary.minecraft.GearyPlugin +import com.mineinabyss.geary.webconsole.GearyWebConsole import com.mineinabyss.idofront.config.IdofrontConfig +import com.mineinabyss.idofront.config.ReloadScope import kotlinx.serialization.Serializable public object GearyConfig : IdofrontConfig(GearyPlugin.instance, Data.serializer()) { @Serializable public class Data( - public val debug: Boolean = false + public val debug: Boolean = false, + public val webConsole: Boolean = true, ) + + private var webConsole: GearyWebConsole? = null + + override fun ReloadScope.load() { + if (data.webConsole) + "Starting web console" { + webConsole = GearyWebConsole() + webConsole?.start() + } + } + + override fun ReloadScope.unload() { + webConsole?.apply { + "Stopping web console" { + stop() + webConsole = null + } + } + } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 44ca20ff4..9f83f7b56 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,4 +1,5 @@ rootProject.name = "geary" +enableFeaturePreview("VERSION_CATALOGS") pluginManagement { val kotlinVersion: String by settings @@ -19,16 +20,37 @@ pluginManagement { } plugins { kotlin("jvm") version kotlinVersion + kotlin("multiplatform") version kotlinVersion kotlin("plugin.serialization") version kotlinVersion id("org.jetbrains.dokka") version dokkaVersion } } +dependencyResolutionManagement { + repositories { + mavenLocal() + } + + versionCatalogs { + create("libs") { + from("com.mineinabyss:catalog:1.6.10-DEV") + } + create("gearylibs") { + version("bimap-test", "1.2") + alias("bimap").to("com.uchuhimo", "kotlinx-bimap").versionRef("bimap-test") + alias("bitvector").to("net.onedaybeard.bitvector:bitvector-jvm:0.1.4") + alias("fastutil").to("it.unimi.dsi:fastutil:8.2.2") //Version on minecraft server + alias("reflections").to("org.reflections:reflections:0.9.12") + alias("plugman").to("com.rylinaux:PlugMan:2.2.5") + } + } +} include( "geary-core", "geary-prefabs", "geary-platform-papermc", + "geary-web-console", ) project(":geary-platform-papermc").projectDir = file("./platforms/geary-platform-papermc") From 45d2a2864dc6043bf3ac0fb1cd784da195437782 Mon Sep 17 00:00:00 2001 From: 0ffz Date: Sun, 23 Jan 2022 01:20:05 -0500 Subject: [PATCH 2/6] Use koin, start splitting papermc into modules, setup compose for web --- README.md | 2 +- geary-core/build.gradle.kts | 4 + .../geary/ecs/accessors/Accessor.kt | 1 - .../building/AccessorBuilderProvider.kt | 3 +- .../geary/ecs/api/engine/Engine.kt | 6 +- .../geary/ecs/api/engine/EngineHelpers.kt | 26 +- .../geary/ecs/api/entities/GearyEntity.kt | 65 +-- .../geary/ecs/api/relations/Relation.kt | 3 +- .../geary/ecs/api/services/GearyServices.kt | 33 -- .../geary/ecs/api/systems/FamilyBuilder.kt | 3 +- .../geary/ecs/api/systems/QueryManager.kt | 4 +- .../mineinabyss/geary/ecs/engine/Archetype.kt | 8 +- .../geary/ecs/engine/ArchetypeHelpers.kt | 7 +- .../geary/ecs/engine/CompId2ArchetypeMap.kt | 7 +- .../geary/ecs/engine/GearyEngine.kt | 29 +- .../mineinabyss/geary/ecs/engine/Record.kt | 4 +- .../geary/ecs/engine/TickingEngine.kt | 4 +- .../geary/ecs/entities/Relationship.kt | 17 +- .../com/mineinabyss/geary/ecs/query/Query.kt | 4 +- .../serialization/GearyEntitySerializer.kt | 7 +- .../geary/ecs/accessors/AccessorHolderTest.kt | 13 +- .../ecs/api/entities/GearyEntityTests.kt | 22 +- .../GearyEntityWithExtensionsKtTest.kt | 14 +- .../geary/ecs/api/systems/QueryManagerTest.kt | 73 ++- .../geary/ecs/engine/ArchetypeTest.kt | 20 +- .../geary/ecs/engine/GearyEngineTest.kt | 54 +-- .../geary/ecs/engine/RecordTest.kt | 19 +- .../ecs/engine/TestGearyServiceProvider.kt | 18 - .../ecs/events/ComponentAddEventKtTest.kt | 16 +- .../geary/ecs/events/SourceTargetEventTest.kt | 18 +- .../query/GearyTypeFamilyExtensionsKtTest.kt | 14 +- .../GearyEntitySerializerKtTest.kt | 6 +- .../mineinabyss/geary/helpers/GearyTest.kt | 43 ++ .../geary/helpers/GearyTestTest.kt | 14 + .../geary/prefabs/PrefabManager.kt | 6 +- .../systems/ParseChildOnPrefab.kt | 5 +- .../geary/prefabs/helpers/PrefabHelpers.kt | 1 - geary-web-console/build.gradle.kts | 21 +- .../ComponentInfo.kt | 20 + .../src/commonMain/resources/index.html | 13 + .../src/commonMain/resources/normalize.css | 427 ++++++++++++++++++ .../src/commonMain/resources/skeleton.css | 418 +++++++++++++++++ geary-web-console/src/jsMain/kotlin/API.kt | 31 ++ geary-web-console/src/jsMain/kotlin/Main.kt | 52 +++ .../src/jsMain/kotlin/components/Layout.kt | 18 + .../geary/webconsole/GearyWebConsole.kt | 68 ++- gradle.properties | 1 + .../geary-platform-papermc/build.gradle.kts | 22 +- .../core/build.gradle.kts | 11 + .../mineinabyss/geary/papermc/GearyConfig.kt | 9 + .../plugin/build.gradle.kts | 28 ++ .../geary/papermc/plugin}/GearyCommands.kt | 3 +- .../geary/papermc/plugin/GearyPlugin.kt | 99 ++++ .../src/main/resources/config.yml | 0 .../src/main/resources/plugin.yml | 0 .../geary/minecraft/GearyPlugin.kt | 90 +--- .../mineinabyss/geary/minecraft/Helpers.kt | 8 +- .../access/BukkitEntityAssociations.kt | 6 +- .../geary/minecraft/config/GearyConfig.kt | 34 -- .../geary/minecraft/dsl/GearyAddon.kt | 4 +- .../geary/minecraft/dsl/GearyLoadManager.kt | 13 +- .../geary/minecraft/engine/SpigotEngine.kt | 16 +- settings.gradle.kts | 9 +- 63 files changed, 1523 insertions(+), 491 deletions(-) delete mode 100644 geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/services/GearyServices.kt delete mode 100644 geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/TestGearyServiceProvider.kt create mode 100644 geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt create mode 100644 geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTestTest.kt create mode 100644 geary-web-console/src/commonMain/kotlin/com.mineinabyss.geary.webconsole.data/ComponentInfo.kt create mode 100644 geary-web-console/src/commonMain/resources/index.html create mode 100644 geary-web-console/src/commonMain/resources/normalize.css create mode 100644 geary-web-console/src/commonMain/resources/skeleton.css create mode 100644 geary-web-console/src/jsMain/kotlin/API.kt create mode 100644 geary-web-console/src/jsMain/kotlin/Main.kt create mode 100644 geary-web-console/src/jsMain/kotlin/components/Layout.kt create mode 100644 platforms/geary-platform-papermc/core/build.gradle.kts create mode 100644 platforms/geary-platform-papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyConfig.kt create mode 100644 platforms/geary-platform-papermc/plugin/build.gradle.kts rename platforms/geary-platform-papermc/{src/main/kotlin/com/mineinabyss/geary/minecraft => plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin}/GearyCommands.kt (96%) create mode 100644 platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPlugin.kt rename platforms/geary-platform-papermc/{ => plugin}/src/main/resources/config.yml (100%) rename platforms/geary-platform-papermc/{ => plugin}/src/main/resources/plugin.yml (100%) delete mode 100644 platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/config/GearyConfig.kt diff --git a/README.md b/README.md index a207b7207..474b17f75 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ class Velocity(...) { An entity to get us started: ```kotlin -Engine.entity { +entity { setAll(Textures(...), Render(...), Velocity(...)) } ``` diff --git a/geary-core/build.gradle.kts b/geary-core/build.gradle.kts index 439fa1d15..ba2a11afb 100644 --- a/geary-core/build.gradle.kts +++ b/geary-core/build.gradle.kts @@ -8,6 +8,8 @@ plugins { } dependencies { + api(libs.koin.core) + //ecs-related libs implementation(gearylibs.bimap) { isTransitive = false } implementation(gearylibs.bitvector) @@ -17,4 +19,6 @@ dependencies { // TODO implementation here, avoid shading on papermc compileOnly(gearylibs.fastutil) testImplementation(gearylibs.fastutil) + testImplementation(libs.koin.test) + testImplementation(libs.koin.test.junit5) } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/Accessor.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/Accessor.kt index cd16dc9c6..c58fe4391 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/Accessor.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/Accessor.kt @@ -41,4 +41,3 @@ public abstract class Accessor( }.also { _cached += it } } - diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/building/AccessorBuilderProvider.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/building/AccessorBuilderProvider.kt index 230855234..b36165b35 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/building/AccessorBuilderProvider.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/building/AccessorBuilderProvider.kt @@ -9,12 +9,13 @@ import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.relations.RelationValueId import com.mineinabyss.geary.ecs.engine.HOLDS_DATA import com.mineinabyss.geary.ecs.engine.withRole +import org.koin.core.component.KoinComponent import kotlin.reflect.typeOf /** * An empty interface that limits [AccessorBuilder] helper functions only to classes that use [Accessor]s. */ -public interface AccessorBuilderProvider +public interface AccessorBuilderProvider: KoinComponent /** Gets a component, ensuring it is on the entity. */ public inline fun AccessorBuilderProvider.get(): AccessorBuilder> { diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/Engine.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/Engine.kt index 26eb4305b..67b102a11 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/Engine.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/Engine.kt @@ -6,13 +6,13 @@ import com.mineinabyss.geary.ecs.api.GearyType import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.relations.Relation import com.mineinabyss.geary.ecs.api.relations.RelationValueId -import com.mineinabyss.geary.ecs.api.services.gearyService import com.mineinabyss.geary.ecs.api.systems.GearySystem import com.mineinabyss.geary.ecs.components.ComponentInfo import com.mineinabyss.geary.ecs.components.RelationComponent import com.mineinabyss.geary.ecs.engine.Archetype import com.mineinabyss.geary.ecs.engine.Record import com.mineinabyss.geary.ecs.events.AddedComponent +import org.koin.core.component.KoinComponent import kotlin.reflect.KClass /** @@ -20,9 +20,7 @@ import kotlin.reflect.KClass * * Its companion object gets a service via Bukkit as its implementation. */ -public interface Engine { - public companion object : Engine by gearyService() - +public interface Engine: KoinComponent { /** The root archetype representing a type of no components */ public val rootArchetype: Archetype diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt index 50d7617e7..b08ad7089 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt @@ -5,18 +5,21 @@ import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.toGeary import com.mineinabyss.geary.ecs.components.ComponentInfo import com.mineinabyss.geary.ecs.serialization.Formats +import org.koin.core.component.KoinComponent +import org.koin.core.component.get +import org.koin.mp.KoinPlatformTools import kotlin.reflect.KClass import kotlin.reflect.KType /** Creates a new empty entity. May reuse recently deleted entity ids. */ -public fun Engine.entity(): GearyEntity = newEntity() +public fun KoinComponent.entity(): GearyEntity = get().newEntity() /** @see entity */ -public inline fun Engine.entity(run: GearyEntity.() -> Unit): GearyEntity = newEntity().apply(run) +public inline fun KoinComponent.entity(run: GearyEntity.() -> Unit): GearyEntity = entity().apply(run) /** Creates a new empty entity that will get removed once [run] completes or fails. */ public inline fun Engine.temporaryEntity(run: (GearyEntity) -> Unit) { - val entity = entity() + val entity = newEntity() try { run(entity) } catch (e: Throwable) { @@ -26,25 +29,32 @@ public inline fun Engine.temporaryEntity(run: (GearyEntity) -> Unit) { } } +public inline fun KoinComponent.temporaryEntity(run: (GearyEntity) -> Unit) { + get().temporaryEntity(run) +} + /** Gets or registers the id of a component of type [T] */ -public inline fun componentId(): GearyComponentId = componentId(T::class) +public inline fun KoinComponent.componentId(): GearyComponentId = componentId(T::class) /** * Gets the id of a component by its serial name. * Throws an error if the component name does not exist. */ -public fun componentId(serialName: String): GearyComponentId = +public fun KoinComponent.componentId(serialName: String): GearyComponentId = componentId(Formats.getClassFor(serialName)) /** Gets or registers the id of a component by its [kType]. */ -public fun componentId(kType: KType): GearyComponentId = componentId(kType.classifier as KClass<*>) +public fun KoinComponent.componentId(kType: KType): GearyComponentId = componentId(kType.classifier as KClass<*>) /** Gets or registers the id of a component by its [kClass]. */ -public fun componentId(kClass: KClass<*>): GearyComponentId = Engine.getOrRegisterComponentIdForClass(kClass) +public fun KoinComponent.componentId(kClass: KClass<*>): GearyComponentId = get().getOrRegisterComponentIdForClass(kClass) @Deprecated("Should not be getting an id for an id!", ReplaceWith("componentId(component)")) @Suppress("UNUSED_PARAMETER") -public fun componentId(kClass: KClass): Nothing = error("Trying to access id for component id") +public fun KoinComponent.componentId(kClass: KClass): Nothing = error("Trying to access id for component id") /** Gets the [ComponentInfo] component from a component's id. */ public fun GearyComponentId.getComponentInfo(): ComponentInfo? = this.toGeary().get() + +@Deprecated("This will be replaced with multi-receiver access in Kotlin 1.6.20") +public val globalEngine: Engine get() = KoinPlatformTools.defaultContext().get().get() diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt index 827257359..cc2aad3a3 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt @@ -9,15 +9,16 @@ import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.engine.temporaryEntity import com.mineinabyss.geary.ecs.api.relations.Relation import com.mineinabyss.geary.ecs.api.relations.RelationValueId +import com.mineinabyss.geary.ecs.api.systems.QueryManager +import com.mineinabyss.geary.ecs.api.systems.family import com.mineinabyss.geary.ecs.components.PersistingComponent import com.mineinabyss.geary.ecs.components.RelationComponent -import com.mineinabyss.geary.ecs.engine.ENTITY_MASK -import com.mineinabyss.geary.ecs.engine.INSTANCEOF -import com.mineinabyss.geary.ecs.engine.Record -import com.mineinabyss.geary.ecs.engine.withRole +import com.mineinabyss.geary.ecs.engine.* import com.mineinabyss.geary.ecs.events.AddedComponent import kotlinx.serialization.Serializable +import org.koin.core.component.KoinComponent import kotlin.reflect.KClass +import org.koin.core.component.get as koinGet /** * A wrapper around [GearyEntityId] that gets inlined to just a long (no performance degradation since no boxing occurs). @@ -27,10 +28,29 @@ import kotlin.reflect.KClass @Serializable @JvmInline @Suppress("NOTHING_TO_INLINE") -public value class GearyEntity(public val id: GearyEntityId) { +public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { + /** Gets the record associated with this entity or throws an error if it is no longer active on the koinGet(). */ + public inline val record: Record get() = koinGet().getRecord(this) + + /** + * Gets this entity's type (the ids of components added to it) + * or throws an error if it is no longer active on the koinGet(). + */ + public inline val type: GearyType get() = record.archetype.type + + public val children: List + get() = koinGet().getEntitiesMatching(family { + has(id.withRole(CHILDOF)) + }) + + public val instances: List + get() = koinGet().getEntitiesMatching(family { + has(id.withRole(INSTANCEOF)) + }) + /** Remove this entity from the ECS. */ public fun removeEntity() { - Engine.removeEntity(this) + koinGet().removeEntity(this) } /** @@ -43,7 +63,7 @@ public value class GearyEntity(public val id: GearyEntityId) { kClass: KClass = T::class, noEvent: Boolean = false ): T { - Engine.setComponentFor(this, componentId(kClass), component, noEvent) + koinGet().setComponentFor(this, componentId(kClass), component, noEvent) return component } @@ -89,7 +109,7 @@ public value class GearyEntity(public val id: GearyEntityId) { valueClass: KClass<*> = value::class, noEvent: Boolean = false ) { - Engine.setComponentFor(this, Relation.of(keyClass, valueClass).id, value, noEvent) + koinGet().setComponentFor(this, Relation.of(keyClass, valueClass).id, value, noEvent) } /** @@ -97,7 +117,7 @@ public value class GearyEntity(public val id: GearyEntityId) { * @param noEvent If true, will not fire an [AddedComponent] event. */ public fun setRelation(key: GearyComponentId, value: Any, noEvent: Boolean = false) { - Engine.setComponentFor(this, Relation.of(key, componentId(value::class)).id, value, noEvent) + koinGet().setComponentFor(this, Relation.of(key, componentId(value::class)).id, value, noEvent) } /** Removes a relation key key of type [K] and value of type [V]. */ @@ -114,7 +134,7 @@ public value class GearyEntity(public val id: GearyEntityId) { /** Removes all relations with a value with id [componentId] on the entity. */ public fun removeRelationsByValue(componentId: GearyComponentId): Set { - val comps = Engine.getRelationsFor(this, RelationValueId(componentId)) + val comps = koinGet().getRelationsFor(this, RelationValueId(componentId)) comps.forEach { (_, relation) -> removeRelation(relation) } @@ -127,7 +147,7 @@ public value class GearyEntity(public val id: GearyEntityId) { * @param noEvent If true, will not fire an [AddedComponent] event. */ public inline fun add(component: GearyComponentId, noEvent: Boolean = false) { - Engine.addComponentFor(this, component, noEvent) + koinGet().addComponentFor(this, component, noEvent) } /** @@ -197,7 +217,7 @@ public value class GearyEntity(public val id: GearyEntityId) { /** Removes a component with id [component] from this entity. */ public inline fun remove(component: GearyComponentId): Boolean = - Engine.removeComponentFor(this, component) + koinGet().removeComponentFor(this, component) /** * Removes a list of [components] from this entity. @@ -209,7 +229,7 @@ public value class GearyEntity(public val id: GearyEntityId) { /** Clears all components on this entity. */ public fun clear() { - Engine.clearEntity(this) + koinGet().clearEntity(this) } /** Gets a component of type [T] on this entity. */ @@ -218,7 +238,7 @@ public value class GearyEntity(public val id: GearyEntityId) { /** Gets a [component] which holds data from this entity. Use [has] if the component is not to hold data. */ public inline fun get(component: GearyComponentId): GearyComponent? = - Engine.getComponentFor(this, component) + koinGet().getComponentFor(this, component) /** Gets a component of type [T] or sets a [default] if no component was present. */ public inline fun getOrSet(kClass: KClass = T::class, default: () -> T): T = @@ -231,7 +251,7 @@ public value class GearyEntity(public val id: GearyEntityId) { ): T = get(kClass) ?: default().also { setPersisting(it, kClass) } /** Gets all the components on this entity, as well as relations in the form of [RelationComponent]. */ - public inline fun getComponents(): Set = Engine.getComponentsFor(this) + public inline fun getComponents(): Set = koinGet().getComponentsFor(this) /** Gets the data in any relations on this entity with a value of type [T]. */ public inline fun getRelationsByValue(): Set = @@ -239,7 +259,7 @@ public value class GearyEntity(public val id: GearyEntityId) { /** Gets the data in any relations on this entity with the value [relationValueId]. */ public inline fun getRelationsByValue(relationValueId: RelationValueId): Set = - Engine.getRelationsFor(this, relationValueId).mapTo(mutableSetOf()) { it.first } + koinGet().getRelationsFor(this, relationValueId).mapTo(mutableSetOf()) { it.first } /** Gets all persisting components on this entity. */ public inline fun getPersistingComponents(): Set = @@ -262,7 +282,7 @@ public value class GearyEntity(public val id: GearyEntityId) { /** Checks whether this entity has a [component], regardless of it holding data. */ public inline fun has(component: GearyComponentId): Boolean = - Engine.hasComponentFor(this, component) + koinGet().hasComponentFor(this, component) /** * Checks whether an entity has all of [components] set or added. @@ -315,7 +335,7 @@ public value class GearyEntity(public val id: GearyEntityId) { result: (event: GearyEntity) -> T, ): T { record.apply { - Engine.temporaryEntity { event -> + koinGet().temporaryEntity { event -> init(event) archetype.callEvent(event, row, source) return result(event) @@ -324,14 +344,5 @@ public value class GearyEntity(public val id: GearyEntityId) { error("Failed to get an entity while calling event that expects a result returned") } - /** Gets the record associated with this entity or throws an error if it is no longer active on the Engine. */ - public inline val record: Record get() = Engine.getRecord(this) - - /** - * Gets this entity's type (the ids of components added to it) - * or throws an error if it is no longer active on the Engine. - */ - public inline val type: GearyType get() = record.archetype.type - public operator fun component1(): GearyEntityId = id } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/relations/Relation.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/relations/Relation.kt index a088c50e4..91c09ede5 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/relations/Relation.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/relations/Relation.kt @@ -8,6 +8,7 @@ import com.mineinabyss.geary.ecs.engine.RELATION_KEY_MASK import com.mineinabyss.geary.ecs.engine.RELATION_VALUE_MASK import com.mineinabyss.geary.ecs.engine.isRelation import kotlinx.serialization.Serializable +import org.koin.core.component.KoinComponent import kotlin.reflect.KClass /** @@ -38,7 +39,7 @@ public value class Relation private constructor( override fun toString(): String = "$key to $value" - public companion object { + public companion object: KoinComponent { public fun of( key: GearyComponentId, value: RelationValueId diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/services/GearyServices.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/services/GearyServices.kt deleted file mode 100644 index e4cacf805..000000000 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/services/GearyServices.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.mineinabyss.geary.ecs.api.services - -import kotlin.reflect.KClass - -//TODO replace with Koin -public object GearyServices { - private val serviceGetters = mutableListOf() - - public fun setServiceProvider(serviceProvider: GearyServiceProvider) { - serviceGetters.clear() - registerServiceProvider(serviceProvider) - } - - public fun registerServiceProvider(serviceProvider: GearyServiceProvider) { - serviceGetters.add(serviceProvider) - } - - public fun getService(kClass: KClass): T? = - serviceGetters.asSequence() - .mapNotNull { it.getService(kClass) } - .firstOrNull() -} - -public interface GearyServiceProvider { - public fun getService(service: KClass): T? -} - -public inline fun gearyService(): T = - gearyServiceOrNull() ?: error("Service ${T::class.simpleName} not found!") - -public inline fun gearyServiceOrNull(): T? = - GearyServices.getService(T::class) - diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/FamilyBuilder.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/FamilyBuilder.kt index 640d59233..ecb5a1720 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/FamilyBuilder.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/FamilyBuilder.kt @@ -7,6 +7,7 @@ import com.mineinabyss.geary.ecs.api.relations.Relation import com.mineinabyss.geary.ecs.api.relations.RelationValueId import com.mineinabyss.geary.ecs.engine.* import com.mineinabyss.geary.ecs.query.* +import org.koin.core.component.KoinComponent import kotlin.reflect.KType public abstract class FamilyBuilder { @@ -40,7 +41,7 @@ public class MutableRelationKeyLeaf( } -public abstract class MutableSelector : FamilyBuilder() { +public abstract class MutableSelector : FamilyBuilder(), KoinComponent { protected abstract val elements: MutableList public val components: List get() = _components diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt index 9384aecec..3c029f1b8 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt @@ -20,7 +20,7 @@ import kotlin.reflect.full.hasAnnotation import kotlin.reflect.jvm.isAccessible import kotlin.reflect.typeOf -public object QueryManager { +public class QueryManager(private val engine: Engine) { private val queries = mutableListOf() private val sourceListeners = mutableListOf() private val targetListeners = mutableListOf() @@ -29,7 +29,7 @@ public object QueryManager { private val archetypes = Component2ObjectArrayMap() init { - registerArchetype(Engine.rootArchetype) + registerArchetype(engine.rootArchetype) } public fun trackEventListener(listener: GearyListener) { diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt index ba75df254..45308d14e 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt @@ -16,6 +16,8 @@ import com.mineinabyss.geary.ecs.query.Query import com.mineinabyss.geary.ecs.query.contains import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject import java.util.* /** @@ -28,7 +30,9 @@ import java.util.* public data class Archetype( public val type: GearyType, public val id: Int -) { +) : KoinComponent { + private val engine by inject() + /** The entity ids in this archetype. Indices are the same as [componentData]'s sub-lists. */ //TODO aim to make private internal val ids = mutableListOf() @@ -293,7 +297,7 @@ public data class Archetype( runningIterators.forEach { it.addMovedRow(lastIndex, row) } - Engine.setRecord(replacement.toGeary(), Record.of(this, row)) + engine.setRecord(replacement.toGeary(), Record.of(this, row)) } } catch (e: IndexOutOfBoundsException) { throw IllegalStateException("Error while removing entity at row $row for archetype $this", e) diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/ArchetypeHelpers.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/ArchetypeHelpers.kt index bf8bc8ba5..d81eaab37 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/ArchetypeHelpers.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/ArchetypeHelpers.kt @@ -4,12 +4,15 @@ import com.mineinabyss.geary.ecs.api.GearyType import com.mineinabyss.geary.ecs.api.engine.Engine import it.unimi.dsi.fastutil.ints.IntOpenHashSet import it.unimi.dsi.fastutil.ints.IntSet +import org.koin.mp.KoinPlatformTools -public fun GearyType.getArchetype(): Archetype = Engine.getArchetype(this) +//TODO use multiple receivers with Kotlin 1.6.20 +public fun GearyType.getArchetype(): Archetype = + KoinPlatformTools.defaultContext().get().get().getArchetype(this) public fun Archetype.countChildren(vis: IntSet = IntOpenHashSet()): Int { componentAddEdges.inner.values.filter { it !in vis } - .forEach { Engine.getArchetype(it).countChildren(vis) } + .forEach { KoinPlatformTools.defaultContext().get().get().getArchetype(it).countChildren(vis) } vis.addAll(componentAddEdges.inner.values) return vis.count() } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/CompId2ArchetypeMap.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/CompId2ArchetypeMap.kt index 24df21272..545deabc1 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/CompId2ArchetypeMap.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/CompId2ArchetypeMap.kt @@ -3,15 +3,18 @@ package com.mineinabyss.geary.ecs.engine import com.mineinabyss.geary.ecs.api.GearyComponentId import com.mineinabyss.geary.ecs.api.engine.Engine import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap +import org.koin.core.component.KoinComponent +import org.koin.core.component.get /** * Inlined class that acts as a map of components to archetypes. Uses archetype ids for better performance. */ @JvmInline -public value class CompId2ArchetypeMap(public val inner: Long2IntOpenHashMap = Long2IntOpenHashMap()) { - public operator fun get(id: GearyComponentId): Archetype = Engine.getArchetype(inner[id.toLong()]) +public value class CompId2ArchetypeMap(public val inner: Long2IntOpenHashMap = Long2IntOpenHashMap()) : KoinComponent { + public operator fun get(id: GearyComponentId): Archetype = get().getArchetype(inner[id.toLong()]) public operator fun set(id: GearyComponentId, archetype: Archetype) { inner[id.toLong()] = archetype.id } + public operator fun contains(id: GearyComponentId): Boolean = inner.containsKey(id.toLong()) } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt index 8964c05cd..b989fe2cb 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt @@ -4,8 +4,6 @@ import com.mineinabyss.geary.ecs.api.GearyComponent import com.mineinabyss.geary.ecs.api.GearyComponentId import com.mineinabyss.geary.ecs.api.GearyEntityId import com.mineinabyss.geary.ecs.api.GearyType -import com.mineinabyss.geary.ecs.api.engine.Engine -import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.engine.temporaryEntity import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.toGeary @@ -17,12 +15,12 @@ import com.mineinabyss.geary.ecs.api.systems.QueryManager import com.mineinabyss.geary.ecs.api.systems.TickingSystem import com.mineinabyss.geary.ecs.components.ComponentInfo import com.mineinabyss.geary.ecs.components.RelationComponent -import com.mineinabyss.geary.ecs.entities.children import com.mineinabyss.geary.ecs.entities.parents import com.mineinabyss.geary.ecs.entities.removeParent import com.mineinabyss.geary.ecs.events.AddedComponent import com.mineinabyss.idofront.messaging.logError import com.mineinabyss.idofront.time.inWholeTicks +import org.koin.core.component.inject import kotlin.reflect.KClass /** @@ -34,6 +32,7 @@ import kotlin.reflect.KClass * Learn more [here](https://github.com/MineInAbyss/Geary/wiki/Basic-ECS-engine-architecture). */ public open class GearyEngine : TickingEngine() { + private val queryManager by inject() private val typeMap = TypeMap() private var currId: GearyEntityId = 0uL final override val rootArchetype: Archetype = Archetype(GearyType(), 0) @@ -41,11 +40,15 @@ public open class GearyEngine : TickingEngine() { private val removedEntities = EntityStack() private val classToComponentMap = ClassToComponentMap() - init { - //Register an entity for the ComponentInfo component, otherwise getComponentIdForClass does a StackOverflow - val componentInfo = entity() - classToComponentMap[ComponentInfo::class] = componentInfo.id -// componentInfo.set(ComponentInfo(ComponentInfo::class)) //FIXME causes an error + override fun start(): Boolean { + return super.start().also { + if (it) { + //Register an entity for the ComponentInfo component, otherwise getComponentIdForClass does a StackOverflow + val componentInfo = newEntity() + classToComponentMap[ComponentInfo::class] = componentInfo.id +// componentInfo.set(ComponentInfo(ComponentInfo::class)) //FIXME causes an error + } + } } private val registeredSystems: MutableSet = mutableSetOf() @@ -73,7 +76,7 @@ public open class GearyEngine : TickingEngine() { } arc.componentRemoveEdges[componentEdge] = prevNode prevNode.componentAddEdges[componentEdge] = arc - QueryManager.registerArchetype(arc) + queryManager.registerArchetype(arc) return arc } @@ -90,12 +93,12 @@ public open class GearyEngine : TickingEngine() { when (system) { is TickingSystem -> { if (system in registeredSystems) return - QueryManager.trackQuery(system) + queryManager.trackQuery(system) registeredSystems.add(system) } is GearyListener -> { if (system in registeredListeners) return - QueryManager.trackEventListener(system) + queryManager.trackEventListener(system) registeredListeners.add(system) } } @@ -147,7 +150,7 @@ public open class GearyEngine : TickingEngine() { val newRecord = archetype.addComponent(entity, row, HOLDS_DATA.inv() and componentId) typeMap[entity] = newRecord ?: return if (!noEvent) - Engine.temporaryEntity { componentAddEvent -> + temporaryEntity { componentAddEvent -> componentAddEvent.setRelation(componentId, AddedComponent(), noEvent = true) newRecord.archetype.callEvent(componentAddEvent, newRecord.row) } @@ -168,7 +171,7 @@ public open class GearyEngine : TickingEngine() { val newRecord = archetype.setComponent(entity, row, componentWithRole, data) typeMap[entity] = newRecord ?: return if (!noEvent) - Engine.temporaryEntity { componentAddEvent -> + temporaryEntity { componentAddEvent -> componentAddEvent.setRelation(componentWithRole, AddedComponent(), noEvent = true) newRecord.archetype.callEvent(componentAddEvent, newRecord.row) } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Record.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Record.kt index 05cae7358..32383070e 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Record.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Record.kt @@ -1,11 +1,11 @@ package com.mineinabyss.geary.ecs.engine -import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.engine.globalEngine @JvmInline public value class Record(public val id: Long) { //Upper 32 bits are row id - public val archetype: Archetype get() = Engine.getArchetype((id shr 32).toInt()) + public val archetype: Archetype get() = globalEngine.getArchetype((id shr 32).toInt()) //Lower 32 bits are row id public val row: Int get() = id.toInt() diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TickingEngine.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TickingEngine.kt index b4566e4c9..3e0564a12 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TickingEngine.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TickingEngine.kt @@ -9,11 +9,13 @@ public abstract class TickingEngine : Engine { //TODO should this be an abstract class and tick be protected? public abstract fun tick(currentTick: Long) - public fun start() { + public open fun start(): Boolean { if (!started) { scheduleSystemTicking() started = true + return true } + return false } public abstract fun scheduleSystemTicking() diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/Relationship.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/Relationship.kt index 739ee67f8..01db0abd7 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/Relationship.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/Relationship.kt @@ -4,9 +4,10 @@ package com.mineinabyss.geary.ecs.entities import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.toGeary -import com.mineinabyss.geary.ecs.api.systems.QueryManager -import com.mineinabyss.geary.ecs.api.systems.family -import com.mineinabyss.geary.ecs.engine.* +import com.mineinabyss.geary.ecs.engine.CHILDOF +import com.mineinabyss.geary.ecs.engine.ENTITY_MASK +import com.mineinabyss.geary.ecs.engine.isChild +import com.mineinabyss.geary.ecs.engine.withRole /** Adds a [parent] entity to this entity. */ public fun GearyEntity.addParent(parent: GearyEntity) { @@ -69,13 +70,3 @@ public val GearyEntity.parents: Set } return parents } - -public val GearyEntity.children: List - get() = QueryManager.getEntitiesMatching(family { - has(id.withRole(CHILDOF)) - }) - -public val GearyEntity.instances: List - get() = QueryManager.getEntitiesMatching(family { - has(id.withRole(INSTANCEOF)) - }) diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/query/Query.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/query/Query.kt index df49fa7af..929d1534d 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/query/Query.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/query/Query.kt @@ -7,12 +7,14 @@ import com.mineinabyss.geary.ecs.accessors.types.ComponentAccessor import com.mineinabyss.geary.ecs.api.GearyComponent import com.mineinabyss.geary.ecs.api.systems.QueryManager import com.mineinabyss.geary.ecs.engine.Archetype +import org.koin.core.component.inject import kotlin.reflect.KProperty /**com.mineinabyss.geary.ecs.engine.iteration.accessors * @property matchedArchetypes A set of archetypes which have been matched to this query. */ public abstract class Query : Iterable, AccessorHolder() { + private val queryManager by inject() internal val matchedArchetypes: MutableSet = mutableSetOf() private var registered = false @@ -20,7 +22,7 @@ public abstract class Query : Iterable, AccessorHolder() { //TODO restrict to calls within the scope of a Query public override fun iterator(): QueryIterator { if (!registered) { - QueryManager.trackQuery(this) + queryManager.trackQuery(this) registered = true } return QueryIterator(this) diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializer.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializer.kt index 7a5cbe861..a9cd9ed0b 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializer.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializer.kt @@ -1,13 +1,11 @@ package com.mineinabyss.geary.ecs.serialization import com.mineinabyss.geary.ecs.api.GearyComponent -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.toGeary import com.mineinabyss.geary.ecs.components.EntityName -import com.mineinabyss.geary.ecs.entities.children import com.mineinabyss.geary.ecs.entities.parent import kotlinx.serialization.KSerializer import kotlinx.serialization.PolymorphicSerializer @@ -15,11 +13,12 @@ import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder +import org.koin.core.component.KoinComponent /** * A serializer which loads a new entity from a list of components. */ -public object GearyEntitySerializer : KSerializer { +public object GearyEntitySerializer : KSerializer, KoinComponent { public val componentListSerializer: KSerializer> = ListSerializer(PolymorphicSerializer(GearyComponent::class)) override val descriptor: SerialDescriptor = componentListSerializer.descriptor @@ -29,7 +28,7 @@ public object GearyEntitySerializer : KSerializer { } override fun deserialize(decoder: Decoder): GearyEntity { - return Engine.entity { + return entity { setAll(decoder.decodeSerializableValue(componentListSerializer)) } } diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/accessors/AccessorHolderTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/accessors/AccessorHolderTest.kt index 458bd5715..3c9164001 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/accessors/AccessorHolderTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/accessors/AccessorHolderTest.kt @@ -3,21 +3,14 @@ package com.mineinabyss.geary.ecs.accessors import com.mineinabyss.geary.ecs.accessors.building.get import com.mineinabyss.geary.ecs.accessors.building.getOrDefault import com.mineinabyss.geary.ecs.accessors.building.map -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.entity -import com.mineinabyss.geary.ecs.engine.GearyEngine -import com.mineinabyss.geary.ecs.engine.setEngineServiceProvider import com.mineinabyss.geary.ecs.query.Query import com.mineinabyss.geary.ecs.query.invoke +import com.mineinabyss.geary.helpers.GearyTest import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test -internal class AccessorHolderTest { - val engine: GearyEngine = GearyEngine() - - init { - setEngineServiceProvider(engine) - } +internal class AccessorHolderTest : GearyTest() { object FancyQuery : Query() { val TargetScope.default by getOrDefault("empty!") @@ -26,7 +19,7 @@ internal class AccessorHolderTest { @Test fun fancyAccessors() { - val entity = Engine.entity() + val entity = entity() //TODO put back when Koin comes // FancyQuery.toList().isEmpty() shouldBe true FancyQuery.none { it.entity == entity } shouldBe true diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/entities/GearyEntityTests.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/entities/GearyEntityTests.kt index 97748b428..5d375b6ae 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/entities/GearyEntityTests.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/entities/GearyEntityTests.kt @@ -1,27 +1,19 @@ package com.mineinabyss.geary.ecs.api.entities -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.components.PersistingComponent -import com.mineinabyss.geary.ecs.engine.GearyEngine import com.mineinabyss.geary.ecs.engine.getArchetype -import com.mineinabyss.geary.ecs.engine.setEngineServiceProvider +import com.mineinabyss.geary.helpers.GearyTest import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test -internal class GearyEntityTests { - val engine: GearyEngine = GearyEngine() - - init { - setEngineServiceProvider(engine) - } - +internal class GearyEntityTests : GearyTest() { @Test fun setPersisting() { - val entity = Engine.entity { + val entity = entity { setPersisting("Test") } val relations = @@ -33,11 +25,11 @@ internal class GearyEntityTests { @Test fun setAllPersisting() { - val entity = Engine.entity { + val entity = entity { set("Test") set(1) } - val entitySetAll = Engine.entity { + val entitySetAll = entity { setAll(listOf("Test", 1)) } entity.type.inner shouldContainExactly entitySetAll.type.inner @@ -45,7 +37,7 @@ internal class GearyEntityTests { @Test fun clear() { - val entity = Engine.entity { + val entity = entity { setPersisting("Test") } val relations = @@ -62,7 +54,7 @@ internal class GearyEntityTests { @Test fun `getRelation reified`() { val testData = TestRelation() - val entity = Engine.entity { + val entity = entity { setRelation(String::class, testData) add() } diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/entities/GearyEntityWithExtensionsKtTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/entities/GearyEntityWithExtensionsKtTest.kt index 83ab0e2d5..a5e60b180 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/entities/GearyEntityWithExtensionsKtTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/entities/GearyEntityWithExtensionsKtTest.kt @@ -1,22 +1,14 @@ package com.mineinabyss.geary.ecs.api.entities -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.entity -import com.mineinabyss.geary.ecs.engine.GearyEngine -import com.mineinabyss.geary.ecs.engine.setEngineServiceProvider +import com.mineinabyss.geary.helpers.GearyTest import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test -internal class GearyEntityWithExtensionsKtTest { - val engine: GearyEngine = GearyEngine() - - init { - setEngineServiceProvider(engine) - } - +internal class GearyEntityWithExtensionsKtTest : GearyTest() { @Test fun nullable_with_extensions() { - val entity = Engine.entity { + val entity = entity { set("") set(1) } diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/systems/QueryManagerTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/systems/QueryManagerTest.kt index 53fd54a44..1c3615c37 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/systems/QueryManagerTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/systems/QueryManagerTest.kt @@ -5,15 +5,13 @@ import com.mineinabyss.geary.ecs.accessors.building.get import com.mineinabyss.geary.ecs.accessors.building.relation import com.mineinabyss.geary.ecs.api.GearyType import com.mineinabyss.geary.ecs.api.autoscan.Handler -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.relations.RelationValueId -import com.mineinabyss.geary.ecs.engine.GearyEngine import com.mineinabyss.geary.ecs.engine.HOLDS_DATA import com.mineinabyss.geary.ecs.engine.getArchetype -import com.mineinabyss.geary.ecs.engine.setEngineServiceProvider import com.mineinabyss.geary.ecs.query.contains +import com.mineinabyss.geary.helpers.GearyTest import io.kotest.matchers.collections.shouldContain import io.kotest.matchers.collections.shouldContainAll import io.kotest.matchers.collections.shouldContainExactly @@ -23,22 +21,13 @@ import io.kotest.matchers.types.shouldBeInstanceOf import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test -internal class QueryManagerTest { - val engine: GearyEngine = GearyEngine() - - init { - setEngineServiceProvider(engine) - } - +internal class QueryManagerTest : GearyTest() { @Nested inner class FamilyMatchingTest { - val entity = Engine.entity { - set("Test") - add() - } - val entity2 = Engine.entity { - set("Test") - set(1) + val stringId = componentId() or HOLDS_DATA + val intId = componentId() + init { + println("Inner class") } val system = object : TickingSystem() { @@ -50,18 +39,16 @@ internal class QueryManagerTest { entity.has() shouldBe true } } - val stringId = componentId() or HOLDS_DATA - val intId = componentId() - val correctArchetype = Engine.rootArchetype + stringId + intId + val correctArchetype = engine.rootArchetype + stringId + intId init { - QueryManager.trackQuery(system) + queryManager.trackQuery(system) } @Test fun `family type is correct`() { - GearyType(system.family.components).getArchetype() shouldBe Engine.rootArchetype + stringId + GearyType(system.family.components).getArchetype() shouldBe engine.rootArchetype + stringId } @Test @@ -71,7 +58,15 @@ internal class QueryManagerTest { @Test fun `get entities matching family`() { - QueryManager.getEntitiesMatching(system.family).apply { + val entity = entity { + set("Test") + add() + } + val entity2 = entity { + set("Test") + set(1) + } + queryManager.getEntitiesMatching(system.family).apply { shouldContainAll(entity, entity2) } } @@ -96,14 +91,14 @@ internal class QueryManagerTest { } init { - QueryManager.trackQuery(removingSystem) + queryManager.trackQuery(removingSystem) } @Test fun `concurrent modification`() { - val entities = (0 until 10).map { Engine.entity { set("Test") } } + val entities = (0 until 10).map { entity { set("Test") } } val total = - QueryManager.getEntitiesMatching(family { + queryManager.getEntitiesMatching(family { hasSet() }).count() removingSystem.doTick() @@ -126,16 +121,16 @@ internal class QueryManagerTest { } } system.family.relationValueTypes.shouldContainExactly(RelationValueId(componentId())) - QueryManager.trackQuery(system) - val entity = Engine.entity { + queryManager.trackQuery(system) + val entity = entity { setRelation(String::class, RelationTestComponent()) add() } - val entity2 = Engine.entity { + val entity2 = entity { setRelation(Int::class, RelationTestComponent()) add() } - val entity3 = Engine.entity { + val entity3 = entity { setRelation(RelationTestComponent::class, "") add() } @@ -162,9 +157,9 @@ internal class QueryManagerTest { test2.value.shouldBeInstanceOf() } } - QueryManager.trackQuery(system) + queryManager.trackQuery(system) - Engine.entity { + entity { setRelation(String::class, RelationTestComponent1()) setRelation(Int::class, RelationTestComponent1()) setRelation(String::class, RelationTestComponent2()) @@ -190,17 +185,17 @@ internal class QueryManagerTest { } } - val entity = Engine.entity { + val entity = entity { setRelation(String::class, RelationTestWithData()) add() } - val entityWithData = Engine.entity { + val entityWithData = entity { setRelation(String::class, RelationTestWithData()) set("Test") } - QueryManager.trackQuery(system) + queryManager.trackQuery(system) system.matchedArchetypes.shouldNotContain(entity.type.getArchetype()) system.matchedArchetypes.shouldContain(entityWithData.type.getArchetype()) @@ -221,10 +216,10 @@ internal class QueryManagerTest { @Test fun `empty event handler`() { - (Engine.rootArchetype.type in EventListener.event.family) shouldBe true - Engine.addSystem(EventListener) - Engine.rootArchetype.eventHandlers.map { it.parentListener } shouldContain EventListener - Engine.entity { + (engine.rootArchetype.type in EventListener.event.family) shouldBe true + engine.addSystem(EventListener) + engine.rootArchetype.eventHandlers.map { it.parentListener } shouldContain EventListener + entity { set(TestComponent()) }.callEvent() // 1 from setting, 1 from calling empty event diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/ArchetypeTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/ArchetypeTest.kt index 11f641f3b..7468297bd 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/ArchetypeTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/ArchetypeTest.kt @@ -1,28 +1,20 @@ package com.mineinabyss.geary.ecs.engine import com.mineinabyss.geary.ecs.api.GearyType -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.relations.Relation import com.mineinabyss.geary.ecs.api.relations.RelationValueId import com.mineinabyss.geary.ecs.components.RelationComponent +import com.mineinabyss.geary.helpers.GearyTest import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.maps.shouldContainKey import io.kotest.matchers.maps.shouldNotContainKey import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance - -@TestInstance(TestInstance.Lifecycle.PER_METHOD) -internal class ArchetypeTest { - val engine: GearyEngine = GearyEngine() - - init { - setEngineServiceProvider(engine) - } +internal class ArchetypeTest : GearyTest() { //TODO bring this back when we switch to Koin DI // @Test // fun `ids assigned correctly`() { @@ -36,18 +28,18 @@ internal class ArchetypeTest { inner class MovingBetweenArchetypes { @Test fun `empty type equals empty archetype`() { - GearyType().getArchetype() shouldBe Engine.rootArchetype + GearyType().getArchetype() shouldBe engine.rootArchetype } @Test fun `get type equals archetype adding`() { - Engine.rootArchetype + 1u + 2u + 3u - 1u + 1u shouldBe + engine.rootArchetype + 1u + 2u + 3u - 1u + 1u shouldBe GearyType(1u, 2u, 3u).getArchetype() } @Test fun `reach same archetype from different starting positions`() { - Engine.rootArchetype + 1u + 2u + 3u shouldBe Engine.rootArchetype + 3u + 2u + 1u + engine.rootArchetype + 1u + 2u + 3u shouldBe engine.rootArchetype + 3u + 2u + 1u } } @@ -71,7 +63,7 @@ internal class ArchetypeTest { @Test fun `getComponents with relations`() { - Engine.entity { + entity { set("Test") setRelation(String::class, 10) setRelation(Int::class, 15) diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/GearyEngineTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/GearyEngineTest.kt index d371fc0ad..7a9ab5e1c 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/GearyEngineTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/GearyEngineTest.kt @@ -1,42 +1,28 @@ package com.mineinabyss.geary.ecs.engine -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.entities.toGeary import com.mineinabyss.geary.ecs.api.relations.Relation import com.mineinabyss.geary.ecs.components.RelationComponent +import com.mineinabyss.geary.helpers.GearyTest import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder import io.kotest.matchers.shouldBe -import io.kotest.matchers.shouldNotBe import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance - -@TestInstance(TestInstance.Lifecycle.PER_METHOD) -internal class GearyEngineTest { - val engine: GearyEngine = GearyEngine() - - init { - setEngineServiceProvider(engine) - } - - @Test - fun `engine service set successfully`() { - Engine.entity { }.id shouldNotBe engine.entity { }.id - } +internal class GearyEngineTest : GearyTest() { @Test fun `adding component to entity`() { - Engine.entity { + entity { set("Test") }.get() shouldBe "Test" } @Test fun `entity has component works via add or set`() { - val entity = Engine.entity { + val entity = entity { add() set(1) } @@ -46,31 +32,31 @@ internal class GearyEngineTest { @Test fun `entity archetype was set`() { - Engine.entity { + entity { add() set(1) - }.type.getArchetype() shouldBe Engine.rootArchetype + componentId() + (HOLDS_DATA or componentId()) + }.type.getArchetype() shouldBe engine.rootArchetype + componentId() + (HOLDS_DATA or componentId()) } @Test fun `component removal`() { - Engine.entity { + entity { set("Test") remove() - }.type.getArchetype() shouldBe Engine.rootArchetype + }.type.getArchetype() shouldBe engine.rootArchetype } @Test fun `add then set`() { - Engine.entity { + entity { add() set("Test") - }.type.getArchetype() shouldBe Engine.rootArchetype + (componentId() or HOLDS_DATA) + }.type.getArchetype() shouldBe engine.rootArchetype + (componentId() or HOLDS_DATA) } @Test fun getComponents() { - Engine.entity { + entity { set("Test") set(1) add() @@ -79,7 +65,7 @@ internal class GearyEngineTest { @Test fun clear() { - val entity = Engine.entity { + val entity = entity { set("Test") add() } @@ -89,7 +75,7 @@ internal class GearyEngineTest { @Test fun setAll() { - Engine.entity { + entity { setAll(listOf("Test", 1)) add() }.getComponents().shouldContainExactlyInAnyOrder("Test", 1) @@ -97,7 +83,7 @@ internal class GearyEngineTest { @Test fun setRelation() { - val entity = Engine.entity { + val entity = entity { setRelation(Int::class, "String to int relation") } entity.type.inner.shouldContainExactly(Relation.of().id.toLong()) @@ -109,24 +95,24 @@ internal class GearyEngineTest { @Test fun `entity removal and reuse`() { //TODO I hate having to do an offset like this, figure out how to reset this Engine singleton via reflection - val offset = Engine.newEntity().id + 1uL + val offset = entity().id + 1uL repeat(10) { - Engine.entity { + entity { add(100uL) } } // We filled up ids 0..9, so next should be at 10 - Engine.newEntity().id shouldBe offset + 10uL + entity().id shouldBe offset + 10uL (0..9).forEach { - Engine.removeEntity((offset + it.toULong()).toGeary()) + engine.removeEntity((offset + it.toULong()).toGeary()) } // Since we removed the first 10 entities, the last entity we removed (at 9) should be the next one that's // ready to be freed up, then 8, etc... - Engine.newEntity().id shouldBe offset + 9uL - Engine.newEntity().id shouldBe offset + 8uL + entity().id shouldBe offset + 9uL + entity().id shouldBe offset + 8uL } } } diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/RecordTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/RecordTest.kt index e31273341..0162ec39a 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/RecordTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/RecordTest.kt @@ -1,24 +1,17 @@ package com.mineinabyss.geary.ecs.engine -import com.mineinabyss.geary.ecs.api.GearyType -import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.helpers.GearyTest import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test -internal class RecordTest { - val engine: GearyEngine = GearyEngine() - - init { - setEngineServiceProvider(engine) - } - +internal class RecordTest : GearyTest() { @Test fun `create record`() { - val record = Record.of(Engine.rootArchetype, 5) - record.archetype shouldBe Engine.rootArchetype + val record = Record.of(engine.rootArchetype, 5) + record.archetype shouldBe engine.rootArchetype record.row shouldBe 5 - val record2 = Record.of(Engine.rootArchetype + 1uL, 6) - record2.archetype shouldBe Engine.rootArchetype + 1uL + val record2 = Record.of(engine.rootArchetype + 1uL, 6) + record2.archetype shouldBe engine.rootArchetype + 1uL record2.row shouldBe 6 } } diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/TestGearyServiceProvider.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/TestGearyServiceProvider.kt deleted file mode 100644 index e8d1c2dbf..000000000 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/engine/TestGearyServiceProvider.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.mineinabyss.geary.ecs.engine - -import com.mineinabyss.geary.ecs.api.engine.Engine -import com.mineinabyss.geary.ecs.api.services.GearyServiceProvider -import com.mineinabyss.geary.ecs.api.services.GearyServices -import kotlin.reflect.KClass - -class TestGearyServiceProvider( - val map: Map, Any> -) : GearyServiceProvider { - override fun getService(service: KClass): T? { - @Suppress("UNCHECKED_CAST") - return map[service] as? T - } -} - -fun setEngineServiceProvider(engine: Engine) = - GearyServices.setServiceProvider(TestGearyServiceProvider(mapOf(Engine::class to engine))) diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/ComponentAddEventKtTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/ComponentAddEventKtTest.kt index 410a6033a..9b25ef6e8 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/ComponentAddEventKtTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/ComponentAddEventKtTest.kt @@ -3,22 +3,14 @@ package com.mineinabyss.geary.ecs.events import com.mineinabyss.geary.ecs.accessors.TargetScope import com.mineinabyss.geary.ecs.accessors.building.get import com.mineinabyss.geary.ecs.api.autoscan.Handler -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.systems.GearyListener -import com.mineinabyss.geary.ecs.engine.GearyEngine import com.mineinabyss.geary.ecs.engine.getArchetype -import com.mineinabyss.geary.ecs.engine.setEngineServiceProvider +import com.mineinabyss.geary.helpers.GearyTest import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test -internal class ComponentAddEventKtTest { - val engine: GearyEngine = GearyEngine() - - init { - setEngineServiceProvider(engine) - } - +internal class ComponentAddEventKtTest : GearyTest() { var inc = 0 //TODO write test for all methods of checking for added @@ -41,9 +33,9 @@ internal class ComponentAddEventKtTest { @Test fun componentAddEvent() { val listener = OnStringAdd() - Engine.addSystem(listener) + engine.addSystem(listener) - Engine.entity { + entity { fun addedListeners() = type.getArchetype().targetListeners.count { it === listener } set("") set(1) diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/SourceTargetEventTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/SourceTargetEventTest.kt index 792f78360..0c6875e31 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/SourceTargetEventTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/SourceTargetEventTest.kt @@ -5,21 +5,13 @@ import com.mineinabyss.geary.ecs.accessors.SourceScope import com.mineinabyss.geary.ecs.accessors.TargetScope import com.mineinabyss.geary.ecs.accessors.building.get import com.mineinabyss.geary.ecs.api.autoscan.Handler -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.systems.GearyListener -import com.mineinabyss.geary.ecs.engine.GearyEngine -import com.mineinabyss.geary.ecs.engine.setEngineServiceProvider +import com.mineinabyss.geary.helpers.GearyTest import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test -class SourceTargetEventTest { - val engine: GearyEngine = GearyEngine() - - init { - setEngineServiceProvider(engine) - } - +class SourceTargetEventTest : GearyTest() { class Strength(val amount: Int) class Attack() data class Health(val amount: Int) @@ -40,11 +32,11 @@ class SourceTargetEventTest { @Test fun interactions() { - Engine.addSystem(Interaction()) - val source = Engine.entity { + engine.addSystem(Interaction()) + val source = entity { set(Strength(10)) } - val target = Engine.entity { + val target = entity { set(Health(10)) } target.get()?.amount shouldBe 10 diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/query/GearyTypeFamilyExtensionsKtTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/query/GearyTypeFamilyExtensionsKtTest.kt index 2d524028a..15ef1a868 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/query/GearyTypeFamilyExtensionsKtTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/query/GearyTypeFamilyExtensionsKtTest.kt @@ -1,23 +1,15 @@ package com.mineinabyss.geary.ecs.query import com.mineinabyss.geary.ecs.api.GearyType -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.relations.Relation import com.mineinabyss.geary.ecs.api.relations.RelationValueId -import com.mineinabyss.geary.ecs.engine.GearyEngine -import com.mineinabyss.geary.ecs.engine.setEngineServiceProvider +import com.mineinabyss.geary.helpers.GearyTest import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test -class GearyTypeFamilyExtensionsKtTest { - val engine: GearyEngine = GearyEngine() - - init { - setEngineServiceProvider(engine) - } - +class GearyTypeFamilyExtensionsKtTest : GearyTest() { @Test fun containsRelation() { val type = GearyType(Relation.of(2uL, 1uL).id, 2uL) @@ -27,7 +19,7 @@ class GearyTypeFamilyExtensionsKtTest { @Test fun contains() { - val type = Engine.entity { setRelation(10uL, "") }.type + val type = entity { setRelation(10uL, "") }.type RelationValueLeaf(RelationValueId(componentId())).contains(type) shouldBe true } } diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializerKtTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializerKtTest.kt index ccdaefaea..d4ce75c47 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializerKtTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializerKtTest.kt @@ -4,11 +4,11 @@ internal class GearyEntitySerializerKtTest { //TODO when gearyAddon isnt so hard to do outside Minecraft // @Test // fun parseEntity() { -// val e = Engine.entity { -// addChild(Engine.entity { +// val e = entity { +// addChild(entity { // set(EntityName("child1")) // }) -// addChild(Engine.entity { +// addChild(entity { // set(EntityName("child2")) // }) // set(ComponentInfo(String::class)) diff --git a/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt new file mode 100644 index 000000000..a492e6a55 --- /dev/null +++ b/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt @@ -0,0 +1,43 @@ +package com.mineinabyss.geary.helpers + +import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.systems.QueryManager +import com.mineinabyss.geary.ecs.engine.GearyEngine +import org.junit.jupiter.api.AfterAll +import org.koin.core.context.startKoin +import org.koin.core.context.stopKoin +import org.koin.dsl.module +import org.koin.test.KoinTest +import org.koin.test.get + +abstract class GearyTest : KoinTest { + val engine get() = get() + val queryManager get() = get() + + init { + startKoinWithGeary() + } + + private fun startKoinWithGeary() { + @Suppress("RemoveExplicitTypeArguments") + startKoin { + modules(module { + val engine = GearyEngine() + val queryManager = QueryManager(engine) + factory { queryManager } + factory { engine } + }) + } + } + + @AfterAll + private fun stop() { + stopKoin() + } + + /** Recreates the engine. */ + fun clearEngine() { + stopKoin() + startKoinWithGeary() + } +} diff --git a/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTestTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTestTest.kt new file mode 100644 index 000000000..aa64222f6 --- /dev/null +++ b/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTestTest.kt @@ -0,0 +1,14 @@ +package com.mineinabyss.geary.helpers + +import io.kotest.matchers.shouldNotBe +import org.junit.jupiter.api.Test + +class GearyTestTest: GearyTest() { + var staticEngine = engine + + @Test + fun `clear engine`() { + clearEngine() + engine shouldNotBe staticEngine + } +} diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManager.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManager.kt index c2af5e428..cd9fc6228 100644 --- a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManager.kt +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManager.kt @@ -1,6 +1,5 @@ package com.mineinabyss.geary.prefabs -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.with @@ -12,6 +11,7 @@ import com.mineinabyss.geary.prefabs.configuration.components.Prefab import com.mineinabyss.idofront.messaging.logError import com.uchuhimo.collections.MutableBiMap import com.uchuhimo.collections.mutableBiMapOf +import org.koin.core.component.KoinComponent import java.io.File /** @@ -19,7 +19,7 @@ import java.io.File * * @property keys A list of registered [PrefabKey]s. */ -public object PrefabManager { +public object PrefabManager: KoinComponent { public val keys: List get() = prefabs.keys.toList() private val prefabs: MutableBiMap = mutableBiMapOf() @@ -59,7 +59,7 @@ public object PrefabManager { "json" -> Formats.jsonFormat else -> error("Unknown file format $ext") } - val entity = writeTo ?: Engine.entity() + val entity = writeTo ?: entity() entity.setAll(format.decodeFromString(GearyEntitySerializer.componentListSerializer, file.readText())) val key = PrefabKey.of(namespace, name) diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseChildOnPrefab.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseChildOnPrefab.kt index d07b989a2..95d5e1479 100644 --- a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseChildOnPrefab.kt +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseChildOnPrefab.kt @@ -4,7 +4,6 @@ import com.mineinabyss.geary.ecs.accessors.TargetScope import com.mineinabyss.geary.ecs.accessors.building.get import com.mineinabyss.geary.ecs.api.autoscan.AutoScan import com.mineinabyss.geary.ecs.api.autoscan.Handler -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.systems.GearyListener import com.mineinabyss.geary.ecs.components.EntityName @@ -22,7 +21,7 @@ public class ParseChildOnPrefab : GearyListener() { @Handler private fun TargetScope.convertToRelation() { - Engine.entity { + entity { addParent(entity) setAll(child.components) } @@ -41,7 +40,7 @@ public class ParseChildrenOnPrefab : GearyListener() { @Handler private fun TargetScope.convertToRelation() { children.nameToComponents.forEach { (name, components) -> - Engine.entity { + entity { addParent(entity) set(EntityName(name)) setAll(components) diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/helpers/PrefabHelpers.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/helpers/PrefabHelpers.kt index 9f6d422fc..42a0d8c08 100644 --- a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/helpers/PrefabHelpers.kt +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/helpers/PrefabHelpers.kt @@ -10,7 +10,6 @@ import com.mineinabyss.geary.ecs.engine.INSTANCEOF import com.mineinabyss.geary.ecs.engine.isInstance import com.mineinabyss.geary.ecs.engine.withRole import com.mineinabyss.geary.ecs.entities.addParent -import com.mineinabyss.geary.ecs.entities.children import com.mineinabyss.geary.prefabs.PrefabKey import com.mineinabyss.geary.prefabs.configuration.components.CopyToInstances diff --git a/geary-web-console/build.gradle.kts b/geary-web-console/build.gradle.kts index 424a4b79c..d97b7d2b9 100644 --- a/geary-web-console/build.gradle.kts +++ b/geary-web-console/build.gradle.kts @@ -1,4 +1,6 @@ -import Com_mineinabyss_conventions_platform_gradle.Deps +import org.jetbrains.compose.compose + +val serverVersion: String by project plugins { java @@ -7,20 +9,24 @@ plugins { id("com.mineinabyss.conventions.platform") // id("com.mineinabyss.conventions.publication") // id("com.mineinabyss.conventions.testing") + id("org.jetbrains.compose") version "1.0.1" } repositories { mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") + google() + maven("https://repo.codemc.io/repository/nms/") + maven("https://papermc.io/repo/repository/maven-public/") } kotlin { jvm { withJava() } - js { - browser { - binaries.executable() - } + js(IR) { + browser() + binaries.executable() } sourceSets { @@ -30,6 +36,7 @@ kotlin { compileOnly(libs.kotlin.stdlib) compileOnly(libs.kotlinx.serialization.json) compileOnly(libs.ktor.client.core) + compileOnly(compose.runtime) } } val commonTest by getting { @@ -41,6 +48,7 @@ kotlin { val jvmMain by getting { dependencies { + compileOnly("io.papermc.paper:paper-api:$serverVersion") compileOnly(project(":geary-core")) compileOnly(libs.kotlin.stdlib) compileOnly(libs.ktor.serialization) @@ -48,6 +56,7 @@ kotlin { compileOnly(libs.ktor.server.netty) compileOnly(libs.logback.classic) compileOnly(libs.kmongo.coroutine.serialization) + compileOnly(project(":geary-platform-papermc")) } } @@ -56,6 +65,8 @@ kotlin { implementation(libs.ktor.client.js) implementation(libs.ktor.client.json) implementation(libs.ktor.client.serialization) + implementation(compose.web.core) + implementation(compose.runtime) } } } diff --git a/geary-web-console/src/commonMain/kotlin/com.mineinabyss.geary.webconsole.data/ComponentInfo.kt b/geary-web-console/src/commonMain/kotlin/com.mineinabyss.geary.webconsole.data/ComponentInfo.kt new file mode 100644 index 000000000..ef783ed66 --- /dev/null +++ b/geary-web-console/src/commonMain/kotlin/com.mineinabyss.geary.webconsole.data/ComponentInfo.kt @@ -0,0 +1,20 @@ +package com.mineinabyss.geary.webconsole.data + +import kotlinx.serialization.Serializable + +@Serializable +data class ComponentInfo( + val name: String, + val data: String, +) { +} + +@Serializable +data class EntityInfo( + val info: String, +// val components: Map, +) { + companion object { + val path = "/entity" + } +} diff --git a/geary-web-console/src/commonMain/resources/index.html b/geary-web-console/src/commonMain/resources/index.html new file mode 100644 index 000000000..7fd74d34a --- /dev/null +++ b/geary-web-console/src/commonMain/resources/index.html @@ -0,0 +1,13 @@ + + + + + Full Stack App! + + + + +
+ + + diff --git a/geary-web-console/src/commonMain/resources/normalize.css b/geary-web-console/src/commonMain/resources/normalize.css new file mode 100644 index 000000000..81c6f31ea --- /dev/null +++ b/geary-web-console/src/commonMain/resources/normalize.css @@ -0,0 +1,427 @@ +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} \ No newline at end of file diff --git a/geary-web-console/src/commonMain/resources/skeleton.css b/geary-web-console/src/commonMain/resources/skeleton.css new file mode 100644 index 000000000..f28bf6c59 --- /dev/null +++ b/geary-web-console/src/commonMain/resources/skeleton.css @@ -0,0 +1,418 @@ +/* +* Skeleton V2.0.4 +* Copyright 2014, Dave Gamache +* www.getskeleton.com +* Free to use under the MIT license. +* http://www.opensource.org/licenses/mit-license.php +* 12/29/2014 +*/ + + +/* Table of contents +–––––––––––––––––––––––––––––––––––––––––––––––––– +- Grid +- Base Styles +- Typography +- Links +- Buttons +- Forms +- Lists +- Code +- Tables +- Spacing +- Utilities +- Clearing +- Media Queries +*/ + + +/* Grid +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.container { + position: relative; + width: 100%; + max-width: 960px; + margin: 0 auto; + padding: 0 20px; + box-sizing: border-box; } +.column, +.columns { + width: 100%; + float: left; + box-sizing: border-box; } + +/* For devices larger than 400px */ +@media (min-width: 400px) { + .container { + width: 85%; + padding: 0; } +} + +/* For devices larger than 550px */ +@media (min-width: 550px) { + .container { + width: 80%; } + .column, + .columns { + margin-left: 4%; } + .column:first-child, + .columns:first-child { + margin-left: 0; } + + .one.column, + .one.columns { width: 4.66666666667%; } + .two.columns { width: 13.3333333333%; } + .three.columns { width: 22%; } + .four.columns { width: 30.6666666667%; } + .five.columns { width: 39.3333333333%; } + .six.columns { width: 48%; } + .seven.columns { width: 56.6666666667%; } + .eight.columns { width: 65.3333333333%; } + .nine.columns { width: 74.0%; } + .ten.columns { width: 82.6666666667%; } + .eleven.columns { width: 91.3333333333%; } + .twelve.columns { width: 100%; margin-left: 0; } + + .one-third.column { width: 30.6666666667%; } + .two-thirds.column { width: 65.3333333333%; } + + .one-half.column { width: 48%; } + + /* Offsets */ + .offset-by-one.column, + .offset-by-one.columns { margin-left: 8.66666666667%; } + .offset-by-two.column, + .offset-by-two.columns { margin-left: 17.3333333333%; } + .offset-by-three.column, + .offset-by-three.columns { margin-left: 26%; } + .offset-by-four.column, + .offset-by-four.columns { margin-left: 34.6666666667%; } + .offset-by-five.column, + .offset-by-five.columns { margin-left: 43.3333333333%; } + .offset-by-six.column, + .offset-by-six.columns { margin-left: 52%; } + .offset-by-seven.column, + .offset-by-seven.columns { margin-left: 60.6666666667%; } + .offset-by-eight.column, + .offset-by-eight.columns { margin-left: 69.3333333333%; } + .offset-by-nine.column, + .offset-by-nine.columns { margin-left: 78.0%; } + .offset-by-ten.column, + .offset-by-ten.columns { margin-left: 86.6666666667%; } + .offset-by-eleven.column, + .offset-by-eleven.columns { margin-left: 95.3333333333%; } + + .offset-by-one-third.column, + .offset-by-one-third.columns { margin-left: 34.6666666667%; } + .offset-by-two-thirds.column, + .offset-by-two-thirds.columns { margin-left: 69.3333333333%; } + + .offset-by-one-half.column, + .offset-by-one-half.columns { margin-left: 52%; } + +} + + +/* Base Styles +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +/* NOTE +html is set to 62.5% so that all the REM measurements throughout Skeleton +are based on 10px sizing. So basically 1.5rem = 15px :) */ +html { + font-size: 62.5%; } +body { + font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */ + line-height: 1.6; + font-weight: 400; + font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #222; } + + +/* Typography +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +h1, h2, h3, h4, h5, h6 { + margin-top: 0; + margin-bottom: 2rem; + font-weight: 300; } +h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;} +h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; } +h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; } +h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; } +h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; } +h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; } + +/* Larger than phablet */ +@media (min-width: 550px) { + h1 { font-size: 5.0rem; } + h2 { font-size: 4.2rem; } + h3 { font-size: 3.6rem; } + h4 { font-size: 3.0rem; } + h5 { font-size: 2.4rem; } + h6 { font-size: 1.5rem; } +} + +p { + margin-top: 0; } + + +/* Links +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +a { + color: #1EAEDB; } +a:hover { + color: #0FA0CE; } + + +/* Buttons +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.button, +button, +input[type="submit"], +input[type="reset"], +input[type="button"] { + display: inline-block; + height: 38px; + padding: 0 30px; + color: #555; + text-align: center; + font-size: 11px; + font-weight: 600; + line-height: 38px; + letter-spacing: .1rem; + text-transform: uppercase; + text-decoration: none; + white-space: nowrap; + background-color: transparent; + border-radius: 4px; + border: 1px solid #bbb; + cursor: pointer; + box-sizing: border-box; } +.button:hover, +button:hover, +input[type="submit"]:hover, +input[type="reset"]:hover, +input[type="button"]:hover, +.button:focus, +button:focus, +input[type="submit"]:focus, +input[type="reset"]:focus, +input[type="button"]:focus { + color: #333; + border-color: #888; + outline: 0; } +.button.button-primary, +button.button-primary, +input[type="submit"].button-primary, +input[type="reset"].button-primary, +input[type="button"].button-primary { + color: #FFF; + background-color: #33C3F0; + border-color: #33C3F0; } +.button.button-primary:hover, +button.button-primary:hover, +input[type="submit"].button-primary:hover, +input[type="reset"].button-primary:hover, +input[type="button"].button-primary:hover, +.button.button-primary:focus, +button.button-primary:focus, +input[type="submit"].button-primary:focus, +input[type="reset"].button-primary:focus, +input[type="button"].button-primary:focus { + color: #FFF; + background-color: #1EAEDB; + border-color: #1EAEDB; } + + +/* Forms +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +input[type="email"], +input[type="number"], +input[type="search"], +input[type="text"], +input[type="tel"], +input[type="url"], +input[type="password"], +textarea, +select { + height: 38px; + padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */ + background-color: #fff; + border: 1px solid #D1D1D1; + border-radius: 4px; + box-shadow: none; + box-sizing: border-box; } +/* Removes awkward default styles on some inputs for iOS */ +input[type="email"], +input[type="number"], +input[type="search"], +input[type="text"], +input[type="tel"], +input[type="url"], +input[type="password"], +textarea { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } +textarea { + min-height: 65px; + padding-top: 6px; + padding-bottom: 6px; } +input[type="email"]:focus, +input[type="number"]:focus, +input[type="search"]:focus, +input[type="text"]:focus, +input[type="tel"]:focus, +input[type="url"]:focus, +input[type="password"]:focus, +textarea:focus, +select:focus { + border: 1px solid #33C3F0; + outline: 0; } +label, +legend { + display: block; + margin-bottom: .5rem; + font-weight: 600; } +fieldset { + padding: 0; + border-width: 0; } +input[type="checkbox"], +input[type="radio"] { + display: inline; } +label > .label-body { + display: inline-block; + margin-left: .5rem; + font-weight: normal; } + + +/* Lists +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +ul { + list-style: circle inside; } +ol { + list-style: decimal inside; } +ol, ul { + padding-left: 0; + margin-top: 0; } +ul ul, +ul ol, +ol ol, +ol ul { + margin: 1.5rem 0 1.5rem 3rem; + font-size: 90%; } +li { + margin-bottom: 1rem; } + + +/* Code +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +code { + padding: .2rem .5rem; + margin: 0 .2rem; + font-size: 90%; + white-space: nowrap; + background: #F1F1F1; + border: 1px solid #E1E1E1; + border-radius: 4px; } +pre > code { + display: block; + padding: 1rem 1.5rem; + white-space: pre; } + + +/* Tables +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +th, +td { + padding: 12px 15px; + text-align: left; + border-bottom: 1px solid #E1E1E1; } +th:first-child, +td:first-child { + padding-left: 0; } +th:last-child, +td:last-child { + padding-right: 0; } + + +/* Spacing +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +button, +.button { + margin-bottom: 1rem; } +input, +textarea, +select, +fieldset { + margin-bottom: 1.5rem; } +pre, +blockquote, +dl, +figure, +table, +p, +ul, +ol, +form { + margin-bottom: 2.5rem; } + + +/* Utilities +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.u-full-width { + width: 100%; + box-sizing: border-box; } +.u-max-full-width { + max-width: 100%; + box-sizing: border-box; } +.u-pull-right { + float: right; } +.u-pull-left { + float: left; } + + +/* Misc +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +hr { + margin-top: 3rem; + margin-bottom: 3.5rem; + border-width: 0; + border-top: 1px solid #E1E1E1; } + + +/* Clearing +–––––––––––––––––––––––––––––––––––––––––––––––––– */ + +/* Self Clearing Goodness */ +.container:after, +.row:after, +.u-cf { + content: ""; + display: table; + clear: both; } + + +/* Media Queries +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +/* +Note: The best way to structure the use of media queries is to create the queries +near the relevant code. For example, if you wanted to change the styles for buttons +on small devices, paste the mobile query code up in the buttons section and style it +there. +*/ + + +/* Larger than mobile */ +@media (min-width: 400px) {} + +/* Larger than phablet (also point when grid becomes active) */ +@media (min-width: 550px) {} + +/* Larger than tablet */ +@media (min-width: 750px) {} + +/* Larger than desktop */ +@media (min-width: 1000px) {} + +/* Larger than Desktop HD */ +@media (min-width: 1200px) {} diff --git a/geary-web-console/src/jsMain/kotlin/API.kt b/geary-web-console/src/jsMain/kotlin/API.kt new file mode 100644 index 000000000..4675120d0 --- /dev/null +++ b/geary-web-console/src/jsMain/kotlin/API.kt @@ -0,0 +1,31 @@ +import com.mineinabyss.geary.webconsole.data.EntityInfo +import io.ktor.client.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.request.* +import kotlinx.browser.window + +val endpoint = window.location.origin // only needed until https://youtrack.jetbrains.com/issue/KTOR-453 is resolved + +val jsonClient = HttpClient { + install(JsonFeature) { serializer = KotlinxSerializer() } +} + +suspend fun getEntityInfo(id: Int): EntityInfo { + return jsonClient.get("$endpoint${EntityInfo.path}/id/$id") +} + +suspend fun getEntityInfo(playerName: String): EntityInfo { + return jsonClient.get("$endpoint${EntityInfo.path}/player/$playerName") +} + +//suspend fun addShoppingListItem(shoppingListItem: ShoppingListItem) { +// jsonClient.post(endpoint + ShoppingListItem.path) { +// contentType(ContentType.Application.Json) +// body = shoppingListItem +// } +//} +// +//suspend fun deleteShoppingListItem(shoppingListItem: ShoppingListItem) { +// jsonClient.delete(endpoint + ShoppingListItem.path + "/${shoppingListItem.id}") +//} diff --git a/geary-web-console/src/jsMain/kotlin/Main.kt b/geary-web-console/src/jsMain/kotlin/Main.kt new file mode 100644 index 000000000..a88a2fb92 --- /dev/null +++ b/geary-web-console/src/jsMain/kotlin/Main.kt @@ -0,0 +1,52 @@ +import QueryOptions.* +import androidx.compose.runtime.* +import com.mineinabyss.geary.webconsole.data.EntityInfo +import components.Container +import components.Row +import kotlinx.coroutines.launch +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.renderComposable + +enum class QueryOptions() { + PLAYER, ID +} + +fun main() { + renderComposable(rootElementId = "root") { + var input by remember { mutableStateOf("") } + var entityInfo: EntityInfo? by remember { mutableStateOf(null) } + val coroutineScope = rememberCoroutineScope() + var queryOption by remember { mutableStateOf(ID) } + + Container { + Row { + TextArea(input) { onInput { input = it.value } } + Button({ + onClick { + coroutineScope.launch { + entityInfo = when (queryOption) { + PLAYER -> getEntityInfo(input) + ID -> getEntityInfo(input.toInt()) + } + } + } + }) { + Text("Search") + } + + Select({ + onChange { queryOption = valueOf(it.value!!) } + }) { + for (option in values()) + Option(option.name) { + Text(option.name) + } + } + entityInfo?.apply { + H1 { Text("Entity Info") } + Text(info) + } + } + } + } +} diff --git a/geary-web-console/src/jsMain/kotlin/components/Layout.kt b/geary-web-console/src/jsMain/kotlin/components/Layout.kt new file mode 100644 index 000000000..95f0bc668 --- /dev/null +++ b/geary-web-console/src/jsMain/kotlin/components/Layout.kt @@ -0,0 +1,18 @@ +package components + +import androidx.compose.runtime.Composable +import org.jetbrains.compose.web.dom.Div + +@Composable +fun Container(content: @Composable () -> Unit) { + Div({ classes("container") }) { + content() + } +} + +@Composable +fun Row(content: @Composable () -> Unit) { + Div({ classes("row") }) { + content() + } +} diff --git a/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt b/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt index 3958f7821..e8d048a37 100644 --- a/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt +++ b/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt @@ -1,10 +1,22 @@ package com.mineinabyss.geary.webconsole +import com.mineinabyss.geary.ecs.api.entities.GearyEntity +import com.mineinabyss.geary.ecs.api.entities.toGeary +import com.mineinabyss.geary.ecs.helpers.listComponents +import com.mineinabyss.geary.minecraft.access.toGeary +import com.mineinabyss.geary.webconsole.data.EntityInfo import io.ktor.application.* +import io.ktor.features.* +import io.ktor.http.* +import io.ktor.http.content.* import io.ktor.response.* import io.ktor.routing.* +import io.ktor.serialization.* import io.ktor.server.engine.* import io.ktor.server.netty.* +import kotlinx.coroutines.GlobalScope.coroutineContext +import org.bukkit.Bukkit +import org.slf4j.LoggerFactory class GearyWebConsole( val port: Int = 9090, @@ -13,13 +25,59 @@ class GearyWebConsole( private var runningServer: NettyApplicationEngine? = null fun start() { - runningServer = embeddedServer(Netty, port = port, host = host) { - routing { - get("/hello") { - call.respondText("Hello world") + runningServer = embeddedServer(Netty, environment = applicationEngineEnvironment { + // Ktor is loaded in our library which is a different classloader + classLoader = GearyWebConsole::class.java.classLoader + this.parentCoroutineContext = coroutineContext + parentCoroutineContext + this.log = LoggerFactory.getLogger("ktor.application") + + connector { + port = this@GearyWebConsole.port + host = this@GearyWebConsole.host + } + + module { + install(ContentNegotiation) { + json() + } + install(CORS) { + method(HttpMethod.Get) + method(HttpMethod.Post) + method(HttpMethod.Delete) + anyHost() + } + + install(Compression) { + gzip() + } + + routing { + get("/") { + call.respondText( + GearyWebConsole::class.java.classLoader.getResource("index.html")!!.readText(), + ContentType.Text.Html + ) + } + static("/") { resources("") } + get("/hello") { + call.respondText("Hello world") + } + route(EntityInfo.path) { + fun infoFor(entity: GearyEntity) = EntityInfo(entity.listComponents()) + get("/id/{id}") { + val entity = call.parameters["id"]?.toULong()?.toGeary() ?: error("Invalid get request") + call.respond(infoFor(entity)) + } + get("/player/{name}") { + val player = + Bukkit.getPlayer(call.parameters["name"]!!) ?: error("No player with that name") + val entity = player.toGeary() + call.respond(infoFor(entity)) + } + } } } - }.start(wait = false) + }).start(wait = false) } fun stop() { diff --git a/gradle.properties b/gradle.properties index 5277091df..c9e6a82f9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,3 +6,4 @@ idofrontConventions=1.6.10-58 kotlinVersion=1.6.10 serverVersion=1.17.1-R0.1-SNAPSHOT dokkaVersion=1.6.0 +kotlin.mpp.stability.nowarn=true diff --git a/platforms/geary-platform-papermc/build.gradle.kts b/platforms/geary-platform-papermc/build.gradle.kts index a3ef660a0..82cb32804 100644 --- a/platforms/geary-platform-papermc/build.gradle.kts +++ b/platforms/geary-platform-papermc/build.gradle.kts @@ -1,38 +1,26 @@ -import Com_mineinabyss_conventions_platform_gradle.Deps - plugins { id("geary.kotlin-conventions") id("com.mineinabyss.conventions.papermc") - id("com.mineinabyss.conventions.publication") - id("com.mineinabyss.conventions.copyjar") kotlin("plugin.serialization") } repositories { maven("https://jitpack.io") - maven("https://raw.githubusercontent.com/TheBlackEntity/PlugMan/repository/") } dependencies { // MineInAbyss platform - compileOnly(Deps.kotlinx.coroutines) - compileOnly(Deps.minecraft.skedule) - compileOnly(Deps.kotlin.reflect) { isTransitive = false } + compileOnly(libs.kotlinx.coroutines) + compileOnly(libs.minecraft.skedule) + compileOnly(libs.kotlin.reflect) { isTransitive = false } + compileOnly(libs.koin.core) - // Other plugins - compileOnly(gearylibs.plugman) // Shaded api(project(":geary-core")) { exclude(module = "kotlin-reflect") } api(project(":geary-prefabs")) - implementation(project(":geary-web-console")) + api(project(":geary-platform-papermc-core")) implementation(gearylibs.reflections) } - -tasks { - shadowJar { - archiveBaseName.set("Geary") - } -} diff --git a/platforms/geary-platform-papermc/core/build.gradle.kts b/platforms/geary-platform-papermc/core/build.gradle.kts new file mode 100644 index 000000000..002492ebf --- /dev/null +++ b/platforms/geary-platform-papermc/core/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("geary.kotlin-conventions") + kotlin("plugin.serialization") +} + +repositories { + maven("https://raw.githubusercontent.com/TheBlackEntity/PlugMan/repository/") +} + +dependencies { +} diff --git a/platforms/geary-platform-papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyConfig.kt b/platforms/geary-platform-papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyConfig.kt new file mode 100644 index 000000000..46d9cfd32 --- /dev/null +++ b/platforms/geary-platform-papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyConfig.kt @@ -0,0 +1,9 @@ +package com.mineinabyss.geary.papermc + +import kotlinx.serialization.Serializable + +@Serializable +public class GearyConfig( + public val debug: Boolean = false, + public val webConsole: Boolean = true, +) diff --git a/platforms/geary-platform-papermc/plugin/build.gradle.kts b/platforms/geary-platform-papermc/plugin/build.gradle.kts new file mode 100644 index 000000000..9461bf909 --- /dev/null +++ b/platforms/geary-platform-papermc/plugin/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + id("geary.kotlin-conventions") + id("com.mineinabyss.conventions.papermc") + id("com.mineinabyss.conventions.publication") + id("com.mineinabyss.conventions.copyjar") + kotlin("plugin.serialization") +} + +repositories { + maven("https://raw.githubusercontent.com/TheBlackEntity/PlugMan/repository/") +} + +dependencies { + // MineInAbyss platform + compileOnly(libs.koin.core) + + // Shaded + implementation(project(":geary-platform-papermc")) + implementation(project(":geary-web-console")) + + // Other plugins + compileOnly(gearylibs.plugman) +} +tasks { + shadowJar { + archiveBaseName.set("Geary") + } +} diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyCommands.kt b/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt similarity index 96% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyCommands.kt rename to platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt index 0486600ff..ec5397025 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyCommands.kt +++ b/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt @@ -1,8 +1,9 @@ -package com.mineinabyss.geary.minecraft +package com.mineinabyss.geary.papermc.plugin import com.mineinabyss.geary.ecs.api.GearyType import com.mineinabyss.geary.ecs.engine.countChildren import com.mineinabyss.geary.ecs.engine.getArchetype +import com.mineinabyss.geary.minecraft.StartupEventListener import com.mineinabyss.geary.prefabs.PrefabKey import com.mineinabyss.geary.prefabs.PrefabManager import com.mineinabyss.idofront.commands.arguments.stringArg diff --git a/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPlugin.kt b/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPlugin.kt new file mode 100644 index 000000000..0af5a9f2d --- /dev/null +++ b/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPlugin.kt @@ -0,0 +1,99 @@ +package com.mineinabyss.geary.papermc.plugin + +import com.mineinabyss.geary.ecs.engine.GearyEngine +import com.mineinabyss.geary.ecs.serialization.Formats +import com.mineinabyss.geary.ecs.serialization.withSerialName +import com.mineinabyss.geary.minecraft.StartupEventListener +import com.mineinabyss.geary.minecraft.access.BukkitAssociations +import com.mineinabyss.geary.minecraft.access.BukkitEntityAssociations +import com.mineinabyss.geary.minecraft.access.toGeary +import com.mineinabyss.geary.minecraft.dsl.GearyLoadPhase +import com.mineinabyss.geary.minecraft.dsl.gearyAddon +import com.mineinabyss.geary.minecraft.engine.SpigotEngine +import com.mineinabyss.geary.minecraft.listeners.GearyAttemptSpawnListener +import com.mineinabyss.geary.minecraft.listeners.InheritPrefabsOnLoad +import com.mineinabyss.geary.minecraft.store.FileSystemStore +import com.mineinabyss.geary.minecraft.store.GearyStore +import com.mineinabyss.geary.papermc.GearyConfig +import com.mineinabyss.geary.webconsole.GearyWebConsole +import com.mineinabyss.idofront.config.singleConfig +import com.mineinabyss.idofront.config.startOrAppendKoin +import com.mineinabyss.idofront.platforms.IdofrontPlatforms +import com.mineinabyss.idofront.plugin.registerEvents +import com.mineinabyss.idofront.plugin.registerService +import com.mineinabyss.idofront.serialization.UUIDSerializer +import org.bukkit.Bukkit +import org.bukkit.plugin.java.JavaPlugin +import org.koin.core.component.KoinComponent +import org.koin.core.component.get +import org.koin.dsl.module +import java.util.* +import kotlin.io.path.div + +public val gearyPlugin: GearyPlugin = Bukkit.getPluginManager().getPlugin("Geary") as GearyPlugin + +public class GearyPlugin : JavaPlugin(), KoinComponent { + override fun onLoad() { + IdofrontPlatforms.load(this, "mineinabyss") + } + + // private var module: Module? = null + @Suppress("RemoveExplicitTypeArguments") + override fun onEnable() { + instance = this + registerEvents(StartupEventListener) + + saveDefaultConfig() + reloadConfig() + startOrAppendKoin(module { + single { this@GearyPlugin } + single { GearyWebConsole() } + single { SpigotEngine(this@GearyPlugin).apply { start() } } + singleConfig(GearyConfig.serializer(), this@GearyPlugin) + }) + + get().start() + + // Register commands. + GearyCommands() + + registerEvents( + BukkitEntityAssociations, + BukkitAssociations, + GearyAttemptSpawnListener, + InheritPrefabsOnLoad(), + ) + + // This will also register a serializer for GearyEntityType + gearyAddon { + autoScanAll() + + components { + //TODO move out to a custom components class + subclass(UUID::class, UUIDSerializer.withSerialName("geary:uuid")) + Formats.registerSerialName("geary:uuid", UUID::class) + } + + dataFolder.listFiles() + ?.filter { it.isDirectory } + ?.forEach { loadPrefabs(it, namespace = it.name) } + + startup { + GearyLoadPhase.ENABLE { + registerService(FileSystemStore(dataFolder.toPath() / "serialized")) + Bukkit.getOnlinePlayers().forEach { it.toGeary() } + } + } + } + } + + override fun onDisable() { + server.scheduler.cancelTasks(this) + get().stop() + } + + public companion object { + /** Gets [GearyPlugin] via Bukkit once, then sends that reference back afterwards */ + public lateinit var instance: GearyPlugin + } +} diff --git a/platforms/geary-platform-papermc/src/main/resources/config.yml b/platforms/geary-platform-papermc/plugin/src/main/resources/config.yml similarity index 100% rename from platforms/geary-platform-papermc/src/main/resources/config.yml rename to platforms/geary-platform-papermc/plugin/src/main/resources/config.yml diff --git a/platforms/geary-platform-papermc/src/main/resources/plugin.yml b/platforms/geary-platform-papermc/plugin/src/main/resources/plugin.yml similarity index 100% rename from platforms/geary-platform-papermc/src/main/resources/plugin.yml rename to platforms/geary-platform-papermc/plugin/src/main/resources/plugin.yml diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt index 7c1499db3..72f598b86 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt @@ -1,93 +1,5 @@ package com.mineinabyss.geary.minecraft -import com.mineinabyss.geary.ecs.api.engine.Engine -import com.mineinabyss.geary.ecs.api.services.GearyServiceProvider -import com.mineinabyss.geary.ecs.api.services.GearyServices -import com.mineinabyss.geary.ecs.serialization.Formats -import com.mineinabyss.geary.ecs.serialization.withSerialName -import com.mineinabyss.geary.minecraft.access.BukkitAssociations -import com.mineinabyss.geary.minecraft.access.BukkitEntityAssociations -import com.mineinabyss.geary.minecraft.access.toGeary -import com.mineinabyss.geary.minecraft.config.GearyConfig -import com.mineinabyss.geary.minecraft.dsl.GearyLoadPhase -import com.mineinabyss.geary.minecraft.dsl.gearyAddon -import com.mineinabyss.geary.minecraft.engine.SpigotEngine -import com.mineinabyss.geary.minecraft.listeners.GearyAttemptSpawnListener -import com.mineinabyss.geary.minecraft.listeners.InheritPrefabsOnLoad -import com.mineinabyss.geary.minecraft.store.FileSystemStore -import com.mineinabyss.geary.minecraft.store.GearyStore -import com.mineinabyss.geary.webconsole.GearyWebConsole -import com.mineinabyss.idofront.platforms.IdofrontPlatforms -import com.mineinabyss.idofront.plugin.registerEvents -import com.mineinabyss.idofront.plugin.registerService -import com.mineinabyss.idofront.serialization.UUIDSerializer -import org.bukkit.Bukkit import org.bukkit.plugin.java.JavaPlugin -import java.util.* -import kotlin.io.path.div -import kotlin.reflect.KClass -public val gearyPlugin: GearyPlugin = Bukkit.getPluginManager().getPlugin("Geary") as GearyPlugin - -public class GearyPlugin : JavaPlugin() { - override fun onLoad() { - IdofrontPlatforms.load(this, "mineinabyss") - } - - override fun onEnable() { - instance = this - registerEvents(StartupEventListener) - - saveDefaultConfig() - reloadConfig() - GearyConfig.load() - GearyServices.setServiceProvider(object : GearyServiceProvider { - override fun getService(service: KClass): T? { - return Bukkit.getServer().servicesManager.load(service.java) - } - }) - - registerService(SpigotEngine().apply { start() }) - - // Register commands. - GearyCommands() - - registerEvents( - BukkitEntityAssociations, - BukkitAssociations, - GearyAttemptSpawnListener, - InheritPrefabsOnLoad(), - ) - - // This will also register a serializer for GearyEntityType - gearyAddon { - autoScanAll() - - components { - //TODO move out to a custom components class - subclass(UUID::class, UUIDSerializer.withSerialName("geary:uuid")) - Formats.registerSerialName("geary:uuid", UUID::class) - } - - dataFolder.listFiles() - ?.filter { it.isDirectory } - ?.forEach { loadPrefabs(it, namespace = it.name) } - - startup { - GearyLoadPhase.ENABLE { - registerService(FileSystemStore(dataFolder.toPath() / "serialized")) - Bukkit.getOnlinePlayers().forEach { it.toGeary() } - } - } - } - } - - override fun onDisable() { - server.scheduler.cancelTasks(this) - } - - public companion object { - /** Gets [GearyPlugin] via Bukkit once, then sends that reference back afterwards */ - public lateinit var instance: GearyPlugin - } -} +public abstract class GearyPlugin: JavaPlugin() diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt index a39f3d902..e4cf7f557 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt @@ -2,10 +2,10 @@ package com.mineinabyss.geary.minecraft import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.minecraft.access.toGeary -import com.mineinabyss.geary.minecraft.config.GearyConfig import com.mineinabyss.geary.minecraft.engine.SpigotEngine import com.mineinabyss.geary.minecraft.events.GearyAttemptMinecraftSpawnEvent import com.mineinabyss.geary.minecraft.events.GearyMinecraftSpawnEvent +import com.mineinabyss.geary.papermc.GearyConfig import com.mineinabyss.geary.prefabs.PrefabKey import com.mineinabyss.geary.prefabs.PrefabManager import com.mineinabyss.geary.prefabs.helpers.addPrefab @@ -16,9 +16,11 @@ import org.bukkit.NamespacedKey import org.bukkit.entity.Entity import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataType +import org.koin.core.component.KoinComponent +import org.koin.core.component.get -internal fun debug(message: Any?) { - if (GearyConfig.data.debug) broadcast(message) +internal fun KoinComponent.debug(message: Any?) { + if (get().debug) broadcast(message) } /** Verifies a [PersistentDataContainer] has a tag identifying it as containing Geary components. */ diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityAssociations.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityAssociations.kt index 23e39affb..e2b532775 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityAssociations.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityAssociations.kt @@ -4,7 +4,6 @@ import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent import com.destroystokyo.paper.event.player.PlayerPostRespawnEvent import com.mineinabyss.geary.ecs.api.GearyComponent -import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.minecraft.events.GearyEntityRemoveEvent @@ -19,11 +18,12 @@ import org.bukkit.event.EventPriority import org.bukkit.event.Listener import org.bukkit.event.player.PlayerJoinEvent import org.bukkit.event.player.PlayerQuitEvent +import org.koin.core.component.KoinComponent internal typealias OnEntityRegister = GearyEntity.(Entity) -> Unit internal typealias OnEntityUnregister = GearyEntity.(Entity) -> Unit -public object BukkitEntityAssociations : Listener { +public object BukkitEntityAssociations : Listener, KoinComponent { //TODO this should be done through events private val onBukkitEntityRegister: MutableList = mutableListOf() private val onBukkitEntityUnregister: MutableList = mutableListOf() @@ -40,7 +40,7 @@ public object BukkitEntityAssociations : Listener { val uuid = entity.uniqueId BukkitAssociations[uuid]?.let { return it } - val gearyEntity = Engine.entity() + val gearyEntity = entity() gearyEntity.apply { setAll( diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/config/GearyConfig.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/config/GearyConfig.kt deleted file mode 100644 index a293428ce..000000000 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/config/GearyConfig.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.mineinabyss.geary.minecraft.config - -import com.mineinabyss.geary.minecraft.GearyPlugin -import com.mineinabyss.geary.webconsole.GearyWebConsole -import com.mineinabyss.idofront.config.IdofrontConfig -import com.mineinabyss.idofront.config.ReloadScope -import kotlinx.serialization.Serializable - -public object GearyConfig : IdofrontConfig(GearyPlugin.instance, Data.serializer()) { - @Serializable - public class Data( - public val debug: Boolean = false, - public val webConsole: Boolean = true, - ) - - private var webConsole: GearyWebConsole? = null - - override fun ReloadScope.load() { - if (data.webConsole) - "Starting web console" { - webConsole = GearyWebConsole() - webConsole?.start() - } - } - - override fun ReloadScope.unload() { - webConsole?.apply { - "Stopping web console" { - stop() - webConsole = null - } - } - } -} diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyAddon.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyAddon.kt index ca59e9d6d..1c55b257e 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyAddon.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyAddon.kt @@ -3,7 +3,7 @@ package com.mineinabyss.geary.minecraft.dsl import com.mineinabyss.geary.ecs.api.GearyComponent import com.mineinabyss.geary.ecs.api.autoscan.AutoScan import com.mineinabyss.geary.ecs.api.autoscan.ExcludeAutoScan -import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.engine.globalEngine import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.systems.GearySystem import com.mineinabyss.geary.ecs.serialization.Formats @@ -138,7 +138,7 @@ public class GearyAddon( /** Registers a [system]. */ public fun system(system: GearySystem) { - Engine.addSystem(system) + globalEngine.addSystem(system) } /** Registers a list of [systems]. */ diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadManager.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadManager.kt index 440ea5ff6..14cdab0bd 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadManager.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadManager.kt @@ -6,8 +6,11 @@ import com.mineinabyss.geary.minecraft.GearyPlugin import com.mineinabyss.geary.minecraft.events.GearyPrefabLoadEvent import com.mineinabyss.idofront.events.call import com.okkero.skedule.schedule +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject -public object GearyLoadManager { +public object GearyLoadManager: KoinComponent { + private val plugin by inject() internal val loadingPrefabs = mutableListOf() private val actions = sortedMapOf Unit>>() @@ -20,12 +23,12 @@ public object GearyLoadManager { private fun MutableList<() -> Unit>.runAll() = forEach { it() } private fun scheduleLoadTasks() { - GearyPlugin.instance.schedule { + plugin.schedule { waitFor(1) - GearyPlugin.instance.logger.info("Registering Serializers") + plugin.logger.info("Registering Serializers") actions[GearyLoadPhase.REGISTER_SERIALIZERS]?.runAll() Formats.createFormats() - GearyPlugin.instance.logger.info("Loading prefabs") + plugin.logger.info("Loading prefabs") actions[GearyLoadPhase.LOAD_PREFABS]?.runAll() loadingPrefabs.forEach { GearyPrefabLoadEvent(it).call() @@ -33,7 +36,7 @@ public object GearyLoadManager { loadingPrefabs.clear() waitFor(1) - GearyPlugin.instance.logger.info("Running final startup tasks") + plugin.logger.info("Running final startup tasks") actions[GearyLoadPhase.ENABLE]?.runAll() actions.clear() } diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt index 41f18cd5e..64024ae28 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt @@ -7,23 +7,25 @@ import com.mineinabyss.geary.ecs.api.systems.TickingSystem import com.mineinabyss.geary.ecs.engine.GearyEngine import com.mineinabyss.geary.minecraft.GearyPlugin import com.mineinabyss.geary.minecraft.events.GearyEntityRemoveEvent -import com.mineinabyss.geary.minecraft.gearyPlugin import com.mineinabyss.idofront.events.call import com.mineinabyss.idofront.plugin.registerEvents import com.okkero.skedule.schedule import org.bukkit.Bukkit import org.bukkit.NamespacedKey import org.bukkit.event.Listener +import org.bukkit.plugin.Plugin +import org.koin.core.component.KoinComponent +import org.koin.core.component.get import java.util.* -public class SpigotEngine : GearyEngine() { - public companion object { - public val componentsKey: NamespacedKey = NamespacedKey(GearyPlugin.instance, "components") +public class SpigotEngine(private val plugin: Plugin) : GearyEngine(), KoinComponent { + public companion object : KoinComponent { + public val componentsKey: NamespacedKey = NamespacedKey(get(), "components") } override fun TickingSystem.runSystem() { // Adds a line in timings report showing which systems take up more time. - val timing = Timings.ofStart(GearyPlugin.instance, javaClass.name) + val timing = Timings.ofStart(plugin, javaClass.name) runCatching { doTick() }.apply { @@ -36,12 +38,12 @@ public class SpigotEngine : GearyEngine() { super.addSystem(system) if (system is Listener) - gearyPlugin.registerEvents(system) + plugin.registerEvents(system) } override fun scheduleSystemTicking() { //tick all systems every interval ticks - GearyPlugin.instance.schedule { + plugin.schedule { repeating(1) while (true) { tick(Bukkit.getServer().currentTick.toLong()) diff --git a/settings.gradle.kts b/settings.gradle.kts index 9f83f7b56..3d33b85fb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,6 +9,8 @@ pluginManagement { repositories { gradlePluginPortal() mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") + google() maven("https://repo.mineinabyss.com/releases") } @@ -49,10 +51,15 @@ dependencyResolutionManagement { include( "geary-core", "geary-prefabs", - "geary-platform-papermc", "geary-web-console", + "geary-platform-papermc", + "geary-platform-papermc-core", + "geary-platform-papermc-plugin", ) project(":geary-platform-papermc").projectDir = file("./platforms/geary-platform-papermc") +project(":geary-platform-papermc-core").projectDir = file("./platforms/geary-platform-papermc/core") +project(":geary-platform-papermc-plugin").projectDir = file("./platforms/geary-platform-papermc/plugin") includeBuild("geary-conventions") +includeBuild("../Idofront") From 56e6d6054dc172c102c244b9497949fdbafda871 Mon Sep 17 00:00:00 2001 From: 0ffz Date: Sun, 23 Jan 2022 13:19:09 -0500 Subject: [PATCH 3/6] Fix plugin load --- .gitignore | 1 + geary-core/build.gradle.kts | 2 +- .../geary/ecs/api/engine/EngineHelpers.kt | 2 +- .../geary/ecs/engine/GearyEngine.kt | 10 +++-- .../geary/ecs/helpers/GearyKoinComponent.kt | 11 ++++++ .../mineinabyss/geary/helpers/GearyTest.kt | 5 ++- .../geary/webconsole/GearyWebConsole.kt | 4 ++ .../geary-platform-papermc/build.gradle.kts | 2 - .../core/build.gradle.kts | 3 -- .../plugin/build.gradle.kts | 8 ++-- .../geary/papermc/plugin/GearyCommands.kt | 8 ++-- .../{GearyPlugin.kt => GearyPluginImpl.kt} | 39 ++++++++++--------- .../plugin/src/main/resources/plugin.yml | 2 +- .../geary/minecraft/GearyPlugin.kt | 4 ++ .../mineinabyss/geary/minecraft/Helpers.kt | 7 ++-- .../geary/minecraft/engine/SpigotEngine.kt | 6 +-- .../geary/minecraft/store/DataStore.kt | 3 +- 17 files changed, 70 insertions(+), 47 deletions(-) create mode 100644 geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/helpers/GearyKoinComponent.kt rename platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/{GearyPlugin.kt => GearyPluginImpl.kt} (78%) diff --git a/.gitignore b/.gitignore index 73eae6590..f267abf5e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ out eclipse *.ipr *.iws +kotlin-js-store/ diff --git a/geary-core/build.gradle.kts b/geary-core/build.gradle.kts index ba2a11afb..c05fd309c 100644 --- a/geary-core/build.gradle.kts +++ b/geary-core/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } dependencies { - api(libs.koin.core) + api(libs.koin.core) { isTransitive = false } //ecs-related libs implementation(gearylibs.bimap) { isTransitive = false } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt index b08ad7089..5e327a522 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt @@ -57,4 +57,4 @@ public fun KoinComponent.componentId(kClass: KClass): Noth public fun GearyComponentId.getComponentInfo(): ComponentInfo? = this.toGeary().get() @Deprecated("This will be replaced with multi-receiver access in Kotlin 1.6.20") -public val globalEngine: Engine get() = KoinPlatformTools.defaultContext().get().get() +public val globalEngine: Engine get() = KoinPlatformTools.defaultContext().get().get() diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt index b989fe2cb..c735f70ff 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt @@ -40,12 +40,16 @@ public open class GearyEngine : TickingEngine() { private val removedEntities = EntityStack() private val classToComponentMap = ClassToComponentMap() + internal fun init() { + //Register an entity for the ComponentInfo component, otherwise getComponentIdForClass does a StackOverflow + val componentInfo = newEntity() + classToComponentMap[ComponentInfo::class] = componentInfo.id + + } override fun start(): Boolean { return super.start().also { if (it) { - //Register an entity for the ComponentInfo component, otherwise getComponentIdForClass does a StackOverflow - val componentInfo = newEntity() - classToComponentMap[ComponentInfo::class] = componentInfo.id + init() // componentInfo.set(ComponentInfo(ComponentInfo::class)) //FIXME causes an error } } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/helpers/GearyKoinComponent.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/helpers/GearyKoinComponent.kt new file mode 100644 index 000000000..f84c3487b --- /dev/null +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/helpers/GearyKoinComponent.kt @@ -0,0 +1,11 @@ +package com.mineinabyss.geary.ecs.helpers + +import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.systems.QueryManager +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject + +public open class GearyKoinComponent: KoinComponent { + public val engine: Engine by inject() + public val queryManager: QueryManager by inject() +} diff --git a/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt index a492e6a55..177075e9c 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt @@ -19,15 +19,16 @@ abstract class GearyTest : KoinTest { } private fun startKoinWithGeary() { + val engine = GearyEngine() + val queryManager = QueryManager(engine) @Suppress("RemoveExplicitTypeArguments") startKoin { modules(module { - val engine = GearyEngine() - val queryManager = QueryManager(engine) factory { queryManager } factory { engine } }) } + engine.init() } @AfterAll diff --git a/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt b/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt index e8d048a37..1a0e25394 100644 --- a/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt +++ b/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt @@ -3,6 +3,7 @@ package com.mineinabyss.geary.webconsole import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.toGeary import com.mineinabyss.geary.ecs.helpers.listComponents +import com.mineinabyss.geary.ecs.helpers.GearyKoinComponent import com.mineinabyss.geary.minecraft.access.toGeary import com.mineinabyss.geary.webconsole.data.EntityInfo import io.ktor.application.* @@ -16,6 +17,7 @@ import io.ktor.server.engine.* import io.ktor.server.netty.* import kotlinx.coroutines.GlobalScope.coroutineContext import org.bukkit.Bukkit +import org.koin.core.component.get import org.slf4j.LoggerFactory class GearyWebConsole( @@ -84,3 +86,5 @@ class GearyWebConsole( runningServer?.stop(1000, 2000) } } + +val GearyKoinComponent.webConsole get() = get() diff --git a/platforms/geary-platform-papermc/build.gradle.kts b/platforms/geary-platform-papermc/build.gradle.kts index 82cb32804..58914f625 100644 --- a/platforms/geary-platform-papermc/build.gradle.kts +++ b/platforms/geary-platform-papermc/build.gradle.kts @@ -13,8 +13,6 @@ dependencies { compileOnly(libs.kotlinx.coroutines) compileOnly(libs.minecraft.skedule) compileOnly(libs.kotlin.reflect) { isTransitive = false } - compileOnly(libs.koin.core) - // Shaded api(project(":geary-core")) { diff --git a/platforms/geary-platform-papermc/core/build.gradle.kts b/platforms/geary-platform-papermc/core/build.gradle.kts index 002492ebf..5ff3abedb 100644 --- a/platforms/geary-platform-papermc/core/build.gradle.kts +++ b/platforms/geary-platform-papermc/core/build.gradle.kts @@ -6,6 +6,3 @@ plugins { repositories { maven("https://raw.githubusercontent.com/TheBlackEntity/PlugMan/repository/") } - -dependencies { -} diff --git a/platforms/geary-platform-papermc/plugin/build.gradle.kts b/platforms/geary-platform-papermc/plugin/build.gradle.kts index 9461bf909..b09b1e666 100644 --- a/platforms/geary-platform-papermc/plugin/build.gradle.kts +++ b/platforms/geary-platform-papermc/plugin/build.gradle.kts @@ -6,14 +6,16 @@ plugins { kotlin("plugin.serialization") } +configurations { + runtimeClasspath { + exclude(group = "io.insert-koin", module = "koin-core") + } +} repositories { maven("https://raw.githubusercontent.com/TheBlackEntity/PlugMan/repository/") } dependencies { - // MineInAbyss platform - compileOnly(libs.koin.core) - // Shaded implementation(project(":geary-platform-papermc")) implementation(project(":geary-web-console")) diff --git a/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt b/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt index ec5397025..a51ade49d 100644 --- a/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt +++ b/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt @@ -13,9 +13,11 @@ import com.mineinabyss.idofront.messaging.info import com.rylinaux.plugman.util.PluginUtil import org.bukkit.command.CommandSender import org.bukkit.command.TabCompleter +import org.bukkit.plugin.Plugin +import org.bukkit.plugin.java.JavaPlugin -internal class GearyCommands : IdofrontCommandExecutor(), TabCompleter { - override val commands = commands(GearyPlugin.instance) { +internal class GearyCommands(val plugin: JavaPlugin) : IdofrontCommandExecutor(), TabCompleter { + override val commands = commands(plugin) { "geary" { "reread" { val prefab by stringArg() @@ -29,7 +31,7 @@ internal class GearyCommands : IdofrontCommandExecutor(), TabCompleter { action { val depends = StartupEventListener.getGearyDependants() depends.forEach { PluginUtil.unload(it) } - PluginUtil.reload(GearyPlugin.instance) + PluginUtil.reload(plugin) depends.forEach { PluginUtil.load(it.name) } } } diff --git a/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPlugin.kt b/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt similarity index 78% rename from platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPlugin.kt rename to platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt index 0af5a9f2d..d6cf193c1 100644 --- a/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPlugin.kt +++ b/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt @@ -1,8 +1,12 @@ package com.mineinabyss.geary.papermc.plugin +import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.systems.QueryManager import com.mineinabyss.geary.ecs.engine.GearyEngine import com.mineinabyss.geary.ecs.serialization.Formats import com.mineinabyss.geary.ecs.serialization.withSerialName +import com.mineinabyss.geary.ecs.helpers.GearyKoinComponent +import com.mineinabyss.geary.minecraft.GearyPlugin import com.mineinabyss.geary.minecraft.StartupEventListener import com.mineinabyss.geary.minecraft.access.BukkitAssociations import com.mineinabyss.geary.minecraft.access.BukkitEntityAssociations @@ -16,6 +20,7 @@ import com.mineinabyss.geary.minecraft.store.FileSystemStore import com.mineinabyss.geary.minecraft.store.GearyStore import com.mineinabyss.geary.papermc.GearyConfig import com.mineinabyss.geary.webconsole.GearyWebConsole +import com.mineinabyss.geary.webconsole.webConsole import com.mineinabyss.idofront.config.singleConfig import com.mineinabyss.idofront.config.startOrAppendKoin import com.mineinabyss.idofront.platforms.IdofrontPlatforms @@ -23,16 +28,12 @@ import com.mineinabyss.idofront.plugin.registerEvents import com.mineinabyss.idofront.plugin.registerService import com.mineinabyss.idofront.serialization.UUIDSerializer import org.bukkit.Bukkit -import org.bukkit.plugin.java.JavaPlugin -import org.koin.core.component.KoinComponent import org.koin.core.component.get import org.koin.dsl.module import java.util.* import kotlin.io.path.div -public val gearyPlugin: GearyPlugin = Bukkit.getPluginManager().getPlugin("Geary") as GearyPlugin - -public class GearyPlugin : JavaPlugin(), KoinComponent { +public class GearyPluginImpl : GearyPlugin() { override fun onLoad() { IdofrontPlatforms.load(this, "mineinabyss") } @@ -40,22 +41,25 @@ public class GearyPlugin : JavaPlugin(), KoinComponent { // private var module: Module? = null @Suppress("RemoveExplicitTypeArguments") override fun onEnable() { - instance = this registerEvents(StartupEventListener) saveDefaultConfig() reloadConfig() + val webConsole = GearyWebConsole() + val engine = SpigotEngine(this@GearyPluginImpl) + val queryManager = QueryManager(engine) startOrAppendKoin(module { - single { this@GearyPlugin } - single { GearyWebConsole() } - single { SpigotEngine(this@GearyPlugin).apply { start() } } - singleConfig(GearyConfig.serializer(), this@GearyPlugin) + single { this@GearyPluginImpl } + single { webConsole } + single { queryManager } + single { engine } + singleConfig(GearyConfig.serializer(), this@GearyPluginImpl) }) - - get().start() + engine.start() + webConsole.start() // Register commands. - GearyCommands() + GearyCommands(this) registerEvents( BukkitEntityAssociations, @@ -89,11 +93,8 @@ public class GearyPlugin : JavaPlugin(), KoinComponent { override fun onDisable() { server.scheduler.cancelTasks(this) - get().stop() - } - - public companion object { - /** Gets [GearyPlugin] via Bukkit once, then sends that reference back afterwards */ - public lateinit var instance: GearyPlugin + GearyKoinComponent().apply { + webConsole.stop() + } } } diff --git a/platforms/geary-platform-papermc/plugin/src/main/resources/plugin.yml b/platforms/geary-platform-papermc/plugin/src/main/resources/plugin.yml index 0d4834076..d873d08c6 100644 --- a/platforms/geary-platform-papermc/plugin/src/main/resources/plugin.yml +++ b/platforms/geary-platform-papermc/plugin/src/main/resources/plugin.yml @@ -2,7 +2,7 @@ name: Geary version: ${plugin_version} author: Offz load: STARTUP -main: com.mineinabyss.geary.minecraft.GearyPlugin +main: com.mineinabyss.geary.papermc.plugin.GearyPluginImpl api-version: 1.17 prefix: Geary diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt index 72f598b86..e1b6cf4a3 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt @@ -1,5 +1,9 @@ package com.mineinabyss.geary.minecraft +import com.mineinabyss.geary.ecs.helpers.GearyKoinComponent import org.bukkit.plugin.java.JavaPlugin +import org.koin.core.component.get public abstract class GearyPlugin: JavaPlugin() + +public val GearyKoinComponent.plugin: GearyPlugin get() = get() diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt index e4cf7f557..804cee478 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt @@ -1,5 +1,6 @@ package com.mineinabyss.geary.minecraft +import com.mineinabyss.geary.ecs.api.engine.globalEngine import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.minecraft.access.toGeary import com.mineinabyss.geary.minecraft.engine.SpigotEngine @@ -25,12 +26,12 @@ internal fun KoinComponent.debug(message: Any?) { /** Verifies a [PersistentDataContainer] has a tag identifying it as containing Geary components. */ public var PersistentDataContainer.hasComponentsEncoded: Boolean - get() = has(SpigotEngine.componentsKey, PersistentDataType.BYTE) + get() = has((globalEngine as SpigotEngine).componentsKey, PersistentDataType.BYTE) set(value) { when { //TODO are there any empty marker keys? - value -> if (!hasComponentsEncoded) set(SpigotEngine.componentsKey, PersistentDataType.BYTE, 1) - else -> remove(SpigotEngine.componentsKey) + value -> if (!hasComponentsEncoded) set((globalEngine as SpigotEngine).componentsKey, PersistentDataType.BYTE, 1) + else -> remove((globalEngine as SpigotEngine).componentsKey) } } diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt index 64024ae28..02c4ae046 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt @@ -5,7 +5,6 @@ import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.systems.GearySystem import com.mineinabyss.geary.ecs.api.systems.TickingSystem import com.mineinabyss.geary.ecs.engine.GearyEngine -import com.mineinabyss.geary.minecraft.GearyPlugin import com.mineinabyss.geary.minecraft.events.GearyEntityRemoveEvent import com.mineinabyss.idofront.events.call import com.mineinabyss.idofront.plugin.registerEvents @@ -15,13 +14,10 @@ import org.bukkit.NamespacedKey import org.bukkit.event.Listener import org.bukkit.plugin.Plugin import org.koin.core.component.KoinComponent -import org.koin.core.component.get import java.util.* public class SpigotEngine(private val plugin: Plugin) : GearyEngine(), KoinComponent { - public companion object : KoinComponent { - public val componentsKey: NamespacedKey = NamespacedKey(get(), "components") - } + public val componentsKey: NamespacedKey = NamespacedKey(plugin, "components") override fun TickingSystem.runSystem() { // Adds a line in timings report showing which systems take up more time. diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/DataStore.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/DataStore.kt index 34cffeb5d..bed07a687 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/DataStore.kt +++ b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/DataStore.kt @@ -2,6 +2,7 @@ package com.mineinabyss.geary.minecraft.store import com.mineinabyss.geary.ecs.api.GearyComponent import com.mineinabyss.geary.ecs.api.GearyType +import com.mineinabyss.geary.ecs.api.engine.globalEngine import com.mineinabyss.geary.ecs.api.entities.toGeary import com.mineinabyss.geary.ecs.engine.isInstance import com.mineinabyss.geary.ecs.serialization.Formats @@ -71,7 +72,7 @@ public inline fun PersistentDataContainer.decode( public fun PersistentDataContainer.encodeComponents(components: Collection, type: GearyType) { hasComponentsEncoded = true //remove all keys present on the PDC so we only end up with the new list of components being encoded - keys.filter { it.namespace == "geary" && it != SpigotEngine.componentsKey }.forEach { remove(it) } + keys.filter { it.namespace == "geary" && it != (globalEngine as SpigotEngine).componentsKey }.forEach { remove(it) } for (value in components) encode(value) From 2feb9053c02881f50afad2156257dfde7379bc9d Mon Sep 17 00:00:00 2001 From: 0ffz Date: Thu, 27 Jan 2022 18:33:25 -0500 Subject: [PATCH 4/6] Refactoring and cleanup old Bukkit events --- .github/workflows/publish-packages.yml | 4 +- README.md | 4 +- build.gradle.kts | 3 +- geary-addon/build.gradle.kts | 14 ++ .../geary/api/addon/AbstractAddonManager.kt | 42 ++++++ .../api/addon/AbstractAddonManagerScope.kt | 5 + .../geary/api/addon/AbstractGearyAddon.kt | 114 +++++++++++++++ .../geary/api/addon}/GearyLoadPhase.kt | 2 +- geary-autoscan/build.gradle.kts | 11 ++ .../mineinabyss/geary/autoscan/AutoScanner.kt | 69 +++++++++ .../geary/autoscan/AutoscanAnnotations.kt | 18 +++ geary-core/build.gradle.kts | 9 +- .../geary/ecs/accessors/AccessorHolder.kt | 4 + .../building/AccessorBuilderProvider.kt | 4 +- .../mineinabyss/geary/ecs/api/GearyType.kt | 2 +- .../Handler.kt} | 18 +-- .../geary/ecs/api/engine/Engine.kt | 6 +- .../geary/ecs/api/engine/EngineHelpers.kt | 39 +++--- .../geary/ecs/api/engine/EngineScope.kt | 7 + .../geary/ecs/api/entities/GearyEntity.kt | 40 ++++-- .../geary/ecs/api/relations/Relation.kt | 10 +- .../geary/ecs/api/systems/FamilyBuilder.kt | 72 +++++++--- .../geary/ecs/api/systems/GearyListener.kt | 25 +++- .../geary/ecs/api/systems/QueryManager.kt | 2 +- .../mineinabyss/geary/ecs/engine/Archetype.kt | 15 +- .../geary/ecs/engine/GearyEngine.kt | 8 +- .../mineinabyss/geary/ecs/engine/Record.kt | 11 +- .../mineinabyss/geary/ecs/engine/TypeRoles.kt | 8 +- .../ecs/entities/RegenerateUUIDOnClash.kt | 3 + .../geary/ecs/entities/UUID2GearyMap.kt | 62 +++++++++ .../geary/ecs/events/EntityRemoved.kt | 3 + .../geary/ecs/helpers/GearyKoinComponent.kt | 12 +- .../serialization/GearyEntitySerializer.kt | 8 +- .../geary/ecs/api/systems/QueryManagerTest.kt | 2 +- .../ecs/events/ComponentAddEventKtTest.kt | 12 +- .../geary/ecs/events/SourceTargetEventTest.kt | 2 +- .../mineinabyss/geary/helpers/GearyTest.kt | 5 +- geary-prefabs/build.gradle.kts | 1 + .../mineinabyss/geary/prefabs/PrefabKey.kt | 9 +- .../geary/prefabs/PrefabManager.kt | 9 +- .../geary/prefabs/PrefabManagerScope.kt | 14 ++ .../systems/ParseChildOnPrefab.kt | 16 +-- .../systems/ParseRelationComponent.kt | 10 +- .../systems/ParseRelationOnPrefab.kt | 10 +- .../geary/prefabs/events/PrefabLoaded.kt | 3 + .../geary/prefabs/helpers/InheritPrefabs.kt | 4 +- .../PrefabByReferenceSerializer.kt | 7 +- geary-web-console/build.gradle.kts | 3 +- .../geary/webconsole/GearyWebConsole.kt | 2 +- .../core/build.gradle.kts | 8 -- .../plugin/build.gradle.kts | 30 ---- .../geary/minecraft/GearyPlugin.kt | 9 -- .../minecraft/access/BukkitAssociations.kt | 43 ------ .../access/BukkitEntityAssociations.kt | 131 ------------------ .../access/BukkitEntityConversion.kt | 16 --- .../geary/minecraft/dsl/GearyLoadManager.kt | 44 ------ .../events/GearyEntityRemoveEvent.kt | 23 --- .../minecraft/events/GearyPrefabLoadEvent.kt | 16 --- .../listeners/GearyAttemptSpawnListener.kt | 15 -- .../listeners/InheritPrefabsOnLoad.kt | 14 -- platforms/papermc/build.gradle.kts | 35 +++++ .../core}/build.gradle.kts | 19 ++- .../mineinabyss/geary/papermc/GearyConfig.kt | 0 .../geary/papermc/GearyMCKoinComponent.kt | 37 +++++ .../mineinabyss/geary/papermc/GearyPlugin.kt | 5 + .../com/mineinabyss/geary/papermc}/Helpers.kt | 24 ++-- .../geary/papermc}/StartupEventListener.kt | 2 +- .../papermc/access/BukkitEntity2Geary.kt | 118 ++++++++++++++++ .../papermc/access/BukkitEntityConversion.kt | 22 +++ .../access/BukkitEntityConversionGenerics.kt | 2 +- .../papermc}/components/BukkitEntityType.kt | 2 +- .../papermc}/components/PrefabKeyHelpers.kt | 2 +- .../geary/papermc}/dsl/AutoScanner.kt | 4 +- .../geary/papermc}/dsl/GearyAddon.kt | 128 ++--------------- .../geary/papermc/dsl/GearyAddonManager.kt | 20 +++ .../geary/papermc/engine/PaperMCEngine.kt} | 15 +- .../events/GearyAttemptMinecraftSpawnEvent.kt | 2 +- .../events/GearyMinecraftSpawnEvent.kt | 2 +- .../papermc/events/GearyPrefabLoadEvent.kt | 2 + .../listeners/GearyAttemptSpawnListener.kt | 17 +++ .../papermc/listeners/InheritPrefabsOnLoad.kt | 21 +++ .../geary/papermc}/store/ContainerHelpers.kt | 2 +- .../geary/papermc}/store/DataStore.kt | 29 ++-- .../geary/papermc}/store/DecodedEntityData.kt | 2 +- .../geary/papermc}/store/FileSystemStore.kt | 2 +- .../geary/papermc}/store/FormatExtensions.kt | 2 +- .../geary/papermc}/store/GearyStore.kt | 2 +- .../papermc}/store/NamespacedKeyHelpers.kt | 2 +- platforms/papermc/plugin/build.gradle.kts | 18 +++ .../geary/papermc/plugin/GearyCommands.kt | 17 ++- .../geary/papermc/plugin/GearyPluginImpl.kt | 48 ++++--- .../plugin/src/main/resources/config.yml | 0 .../plugin/src/main/resources/plugin.yml | 0 settings.gradle.kts | 20 ++- 94 files changed, 1004 insertions(+), 731 deletions(-) create mode 100644 geary-addon/build.gradle.kts create mode 100644 geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractAddonManager.kt create mode 100644 geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractAddonManagerScope.kt create mode 100644 geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractGearyAddon.kt rename {platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl => geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon}/GearyLoadPhase.kt (68%) create mode 100644 geary-autoscan/build.gradle.kts create mode 100644 geary-autoscan/src/main/kotlin/com/mineinabyss/geary/autoscan/AutoScanner.kt create mode 100644 geary-autoscan/src/main/kotlin/com/mineinabyss/geary/autoscan/AutoscanAnnotations.kt rename geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/{autoscan/AutoscanAnnotations.kt => annotations/Handler.kt} (62%) create mode 100644 geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineScope.kt create mode 100644 geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/RegenerateUUIDOnClash.kt create mode 100644 geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/UUID2GearyMap.kt create mode 100644 geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/events/EntityRemoved.kt create mode 100644 geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManagerScope.kt create mode 100644 geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/events/PrefabLoaded.kt delete mode 100644 platforms/geary-platform-papermc/core/build.gradle.kts delete mode 100644 platforms/geary-platform-papermc/plugin/build.gradle.kts delete mode 100644 platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt delete mode 100644 platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitAssociations.kt delete mode 100644 platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityAssociations.kt delete mode 100644 platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityConversion.kt delete mode 100644 platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadManager.kt delete mode 100644 platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyEntityRemoveEvent.kt delete mode 100644 platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyPrefabLoadEvent.kt delete mode 100644 platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/listeners/GearyAttemptSpawnListener.kt delete mode 100644 platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/listeners/InheritPrefabsOnLoad.kt create mode 100644 platforms/papermc/build.gradle.kts rename platforms/{geary-platform-papermc => papermc/core}/build.gradle.kts (62%) rename platforms/{geary-platform-papermc => papermc}/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyConfig.kt (100%) create mode 100644 platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyMCKoinComponent.kt create mode 100644 platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyPlugin.kt rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/Helpers.kt (62%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/StartupEventListener.kt (94%) create mode 100644 platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntity2Geary.kt create mode 100644 platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntityConversion.kt rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/access/BukkitEntityConversionGenerics.kt (85%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/components/BukkitEntityType.kt (82%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/components/PrefabKeyHelpers.kt (87%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/dsl/AutoScanner.kt (96%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/dsl/GearyAddon.kt (51%) create mode 100644 platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/dsl/GearyAddonManager.kt rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/engine/PaperMCEngine.kt} (71%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/events/GearyAttemptMinecraftSpawnEvent.kt (91%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/events/GearyMinecraftSpawnEvent.kt (92%) create mode 100644 platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/events/GearyPrefabLoadEvent.kt create mode 100644 platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/listeners/GearyAttemptSpawnListener.kt create mode 100644 platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/listeners/InheritPrefabsOnLoad.kt rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/store/ContainerHelpers.kt (97%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/store/DataStore.kt (85%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/store/DecodedEntityData.kt (83%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/store/FileSystemStore.kt (97%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/store/FormatExtensions.kt (94%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/store/GearyStore.kt (95%) rename platforms/{geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft => papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc}/store/NamespacedKeyHelpers.kt (97%) create mode 100644 platforms/papermc/plugin/build.gradle.kts rename platforms/{geary-platform-papermc => papermc}/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt (84%) rename platforms/{geary-platform-papermc => papermc}/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt (67%) rename platforms/{geary-platform-papermc => papermc}/plugin/src/main/resources/config.yml (100%) rename platforms/{geary-platform-papermc => papermc}/plugin/src/main/resources/plugin.yml (100%) diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml index 6f8e08097..1295f6aa2 100644 --- a/.github/workflows/publish-packages.yml +++ b/.github/workflows/publish-packages.yml @@ -41,7 +41,7 @@ jobs: shell: bash id: extract_version run: | - version=`./gradlew :geary-platform-papermc:properties --no-daemon --console=plain -q | grep "^version:" | awk '{printf $2}'` + version=`./gradlew :geary-papermc-core:properties --no-daemon --console=plain -q | grep "^version:" | awk '{printf $2}'` echo "::set-output name=version::$version" - name: Create GitHub Release @@ -51,4 +51,4 @@ jobs: prerelease: false automatic_release_tag: v${{ steps.extract_version.outputs.version }} files: | - platforms/geary-platform-papermc/build/libs/*-all.jar + platforms/geary-papermc-core/build/libs/*-all.jar diff --git a/README.md b/README.md index 474b17f75..6b43adce5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Geary [![Java CI with Gradle](https://github.com/MineInAbyss/Geary/actions/workflows/gradle-ci.yml/badge.svg)](https://github.com/MineInAbyss/Geary/actions/workflows/gradle-ci.yml) -[![Package](https://img.shields.io/maven-metadata/v?metadataUrl=https://repo.mineinabyss.com/releases/com/mineinabyss/geary-platform-papermc/maven-metadata.xml)](https://repo.mineinabyss.com/#/releases/com/mineinabyss/geary-platform-papermc) +[![Package](https://img.shields.io/maven-metadata/v?metadataUrl=https://repo.mineinabyss.com/releases/com/mineinabyss/geary-papermc-core/maven-metadata.xml)](https://repo.mineinabyss.com/#/releases/com/mineinabyss/geary-papermc-core) [![Wiki](https://img.shields.io/badge/-Project%20Wiki-blueviolet?logo=Wikipedia&labelColor=gray)](https://wiki.mineinabyss.com/geary) [![Contribute](https://shields.io/badge/Contribute-e57be5?logo=github%20sponsors&style=flat&logoColor=white)](https://wiki.mineinabyss.com/contribute) @@ -124,7 +124,7 @@ repositories { dependencies { compileOnly 'com.mineinabyss:geary:' // Use the line below if you want to use Geary for your PaperMC plugin - compileOnly 'com.mineinabyss:geary-platform-papermc:' + compileOnly 'com.mineinabyss:geary-papermc-core:' } ``` diff --git a/build.gradle.kts b/build.gradle.kts index 4365c397d..9444e61c4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,8 +3,9 @@ plugins { // kotlin("multiplatform") // id("org.jetbrains.dokka") } + tasks { build { - dependsOn(project(":geary-platform-papermc").tasks.build) + dependsOn(project(":geary-papermc").tasks.build) } } diff --git a/geary-addon/build.gradle.kts b/geary-addon/build.gradle.kts new file mode 100644 index 000000000..cb024e84b --- /dev/null +++ b/geary-addon/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("geary.kotlin-conventions") + kotlin("plugin.serialization") + id("com.mineinabyss.conventions.publication") + id("com.mineinabyss.conventions.testing") +} + +dependencies { +// implementation(libs.kotlinx.coroutines) + implementation(libs.reflections) + implementation(libs.kotlin.reflect) + compileOnly(project(":geary-core")) + compileOnly(project(":geary-prefabs")) +} diff --git a/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractAddonManager.kt b/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractAddonManager.kt new file mode 100644 index 000000000..8d8e9bb18 --- /dev/null +++ b/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractAddonManager.kt @@ -0,0 +1,42 @@ +package com.mineinabyss.geary.api.addon + +import com.mineinabyss.geary.ecs.api.entities.GearyEntity +import com.mineinabyss.geary.ecs.serialization.Formats +import com.mineinabyss.geary.prefabs.events.PrefabLoaded +import com.mineinabyss.idofront.messaging.logInfo +import org.koin.core.component.KoinComponent + +public abstract class AbstractAddonManager : KoinComponent { + internal val loadingPrefabs = mutableListOf() + private val actions = sortedMapOf Unit>>() + + public fun add(phase: GearyLoadPhase, action: () -> Unit) { + if (actions.isEmpty()) scheduleLoadTasks() + + actions.getOrPut(phase) { mutableListOf() }.add(action) + } + + protected abstract fun scheduleLoadTasks() + + private fun MutableList<() -> Unit>.runAll() = forEach { it() } + + /** Tasks to run before all other addon startup tasks execute. */ + public fun load() { + logInfo("Registering Serializers") + actions[GearyLoadPhase.REGISTER_SERIALIZERS]?.runAll() + Formats.createFormats() + logInfo("Loading prefabs") + actions[GearyLoadPhase.LOAD_PREFABS]?.runAll() + loadingPrefabs.forEach { + it.callEvent(PrefabLoaded()) + } + loadingPrefabs.clear() + } + + /** Run addons startup tasks. */ + public fun enableAddons() { + logInfo("Running final startup tasks") + actions[GearyLoadPhase.ENABLE]?.runAll() + actions.clear() + } +} diff --git a/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractAddonManagerScope.kt b/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractAddonManagerScope.kt new file mode 100644 index 000000000..86c36b36a --- /dev/null +++ b/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractAddonManagerScope.kt @@ -0,0 +1,5 @@ +package com.mineinabyss.geary.api.addon + +public interface AbstractAddonManagerScope { + public val addonManager: AbstractAddonManager +} diff --git a/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractGearyAddon.kt b/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractGearyAddon.kt new file mode 100644 index 000000000..80abc3a19 --- /dev/null +++ b/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/AbstractGearyAddon.kt @@ -0,0 +1,114 @@ +package com.mineinabyss.geary.api.addon + +import com.mineinabyss.geary.ecs.api.GearyComponent +import com.mineinabyss.geary.ecs.api.engine.EngineScope +import com.mineinabyss.geary.ecs.api.systems.GearySystem +import com.mineinabyss.geary.ecs.serialization.Formats +import com.mineinabyss.geary.prefabs.PrefabManagerScope +import kotlinx.serialization.KSerializer +import kotlinx.serialization.modules.PolymorphicModuleBuilder +import kotlinx.serialization.modules.SerializersModule +import kotlinx.serialization.modules.SerializersModuleBuilder +import kotlinx.serialization.modules.polymorphic +import java.io.File +import kotlin.reflect.KClass + +@DslMarker +@Retention(AnnotationRetention.SOURCE) +public annotation class GearyAddonDSL + +/** + * The entry point for other plugins to hook into Geary. Allows registering serializable components, systems, actions, + * and more. + */ +@GearyAddonDSL +public abstract class AbstractGearyAddon : EngineScope, AbstractAddonManagerScope, PrefabManagerScope { + public abstract val namespace: String + + /** Adds a [SerializersModule] for polymorphic serialization of [GearyComponent]s within the ECS. */ + public inline fun components(crossinline init: PolymorphicModuleBuilder.() -> Unit) { + serializers { polymorphic(GearyComponent::class) { init() } } + } + + /** Registers a [system]. */ + public fun system(system: GearySystem) { + engine.addSystem(system) + } + + /** Registers a list of [systems]. */ + public fun systems(vararg systems: GearySystem) { + systems.forEach { system(it) } + } + + /** + * Adds a serializable component and registers it with Geary to allow finding the appropriate class via + * component serial name. + */ + public inline fun PolymorphicModuleBuilder.component(serializer: KSerializer) { + component(T::class, serializer) + } + + /** + * Adds a serializable component and registers it with Geary to allow finding the appropriate class via + * component serial name. + */ + public fun PolymorphicModuleBuilder.component( + kClass: KClass, + serializer: KSerializer? + ): Boolean { + val serialName = serializer?.descriptor?.serialName ?: return false + if (!Formats.isRegistered(serialName)) { + Formats.registerSerialName(serialName, kClass) + subclass(kClass, serializer) + return true + } + return false + } + + /** Adds a [SerializersModule] to be used for polymorphic serialization within the ECS. */ + public inline fun serializers(init: SerializersModuleBuilder.() -> Unit) { + Formats.addSerializerModule(namespace, SerializersModule { init() }) + } + + /** Loads prefab entities from all files inside a [directory][from], into a given [namespace] */ + public fun loadPrefabs( + from: File, + namespace: String = this.namespace + ) { + startup { + GearyLoadPhase.LOAD_PREFABS { + // Start with the innermost directories + val dirs = from.walkBottomUp().filter { it.isDirectory } + val files = dirs.flatMap { dir -> dir.walk().maxDepth(1).filter { it.isFile } } + files.forEach { file -> + val entity = prefabManager.loadFromFile(namespace, file) ?: return@forEach + addonManager.loadingPrefabs += entity + } + } + } + } + + public inner class PhaseCreator { + public operator fun GearyLoadPhase.invoke(run: () -> Unit) { + addonManager.add(this, run) + } + } + + /** + * Allows defining actions that should run at a specific phase during startup + * + * Within its context, invoke a [GearyLoadPhase] to run something during it, ex: + * + * ``` + * GearyLoadPhase.ENABLE { + * // run code here + * } + * ``` + */ + public inline fun startup(run: PhaseCreator.() -> Unit) { + PhaseCreator().apply(run) + } +} + +/** The polymorphic builder scope that allows registering subclasses. */ +public typealias SerializerRegistry = PolymorphicModuleBuilder.(kClass: KClass, serializer: KSerializer?) -> Boolean diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadPhase.kt b/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/GearyLoadPhase.kt similarity index 68% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadPhase.kt rename to geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/GearyLoadPhase.kt index 82a22c17a..f182509fa 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadPhase.kt +++ b/geary-addon/src/main/kotlin/com/mineinabyss/geary/api/addon/GearyLoadPhase.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.dsl +package com.mineinabyss.geary.api.addon public enum class GearyLoadPhase { REGISTER_SERIALIZERS, diff --git a/geary-autoscan/build.gradle.kts b/geary-autoscan/build.gradle.kts new file mode 100644 index 000000000..b0e3a5f11 --- /dev/null +++ b/geary-autoscan/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("geary.kotlin-conventions") +// kotlin("plugin.serialization") +// id("com.mineinabyss.conventions.publication") +// id("com.mineinabyss.conventions.testing") +} + +dependencies { + api(libs.reflections) + compileOnly(project(":geary-core")) +} diff --git a/geary-autoscan/src/main/kotlin/com/mineinabyss/geary/autoscan/AutoScanner.kt b/geary-autoscan/src/main/kotlin/com/mineinabyss/geary/autoscan/AutoScanner.kt new file mode 100644 index 000000000..31eccd7f0 --- /dev/null +++ b/geary-autoscan/src/main/kotlin/com/mineinabyss/geary/autoscan/AutoScanner.kt @@ -0,0 +1,69 @@ +package com.mineinabyss.geary.autoscan + +import com.mineinabyss.idofront.messaging.logWarn +import org.reflections.Reflections +import org.reflections.scanners.SubTypesScanner +import org.reflections.util.ClasspathHelper +import org.reflections.util.ConfigurationBuilder +import org.reflections.util.FilterBuilder +import kotlin.reflect.KClass + +/** + * DSL for configuring automatic scanning of classes to be registered into Geary's [SerializersModule]. + * + * A [path] to limit search to may be specified. Specific packages can also be excluded with [excludePath]. + * Annotate a class with [ExcludeAutoScan] to exclude it from automatically being registered. + * + * _Note that if the plugin is loaded using a custom classloading solution, autoscan may not work._ + * + * @property path Optional path to restrict what packages are scanned. + * @property excluded Excluded paths under [path]. + */ +public class AutoScanner(private val classLoader: ClassLoader) { + public var path: String? = null + private val excluded = mutableListOf() + + /** Add a path to be excluded from the scanner. */ + public fun excludePath(path: String) { + excluded += path + } + + /** Gets a reflections object under [path] */ + public fun getReflections(): Reflections? { + // cache the object we get because it takes considerable amount of time to get + val cacheKey = CacheKey(classLoader, path, excluded) + reflectionsCache[cacheKey]?.let { return it } + + val reflections = Reflections( + ConfigurationBuilder() + .addClassLoader(classLoader) + .addUrls(ClasspathHelper.forClassLoader(classLoader)) + .addScanners(SubTypesScanner()) + .filterInputsBy(FilterBuilder().apply { + if (path != null) includePackage(path) + excluded.forEach { excludePackage(it) } + }) + ) + + reflectionsCache[cacheKey] = reflections + + // Check if the store is empty. Since we only use a single SubTypesScanner, if this is empty + // then the path passed in returned 0 matches. + if (reflections.store.keySet().isEmpty()) { + logWarn("Autoscanner failed to find classes for ${classLoader}${if (path == null) "" else " in package ${path}}"}.") + return null + } + return reflections + } + + public inline fun getSubclassesOf(): List> { + return getReflections()?.getSubTypesOf(T::class.java)?.map { it.kotlin } ?: listOf() + } + + + private companion object { + private data class CacheKey(val classLoader: ClassLoader, val path: String?, val excluded: Collection) + + private val reflectionsCache = mutableMapOf() + } +} diff --git a/geary-autoscan/src/main/kotlin/com/mineinabyss/geary/autoscan/AutoscanAnnotations.kt b/geary-autoscan/src/main/kotlin/com/mineinabyss/geary/autoscan/AutoscanAnnotations.kt new file mode 100644 index 000000000..f2b206344 --- /dev/null +++ b/geary-autoscan/src/main/kotlin/com/mineinabyss/geary/autoscan/AutoscanAnnotations.kt @@ -0,0 +1,18 @@ +package com.mineinabyss.geary.autoscan + +import com.mineinabyss.geary.ecs.api.systems.GearyListener +import com.mineinabyss.geary.ecs.api.systems.GearySystem +import com.mineinabyss.geary.ecs.api.systems.TickingSystem +import com.mineinabyss.geary.ecs.query.Query + +/** + * Excludes this class from having its serializer automatically registered for component serialization + * with the AutoScanner. + */ +public annotation class ExcludeAutoScan + +/** + * Indicates this [GearySystem], such as [TickingSystem], [GearyListener], or [Query] be registered automatically + * on startup by the AutoScanner. + */ +public annotation class AutoScan diff --git a/geary-core/build.gradle.kts b/geary-core/build.gradle.kts index c05fd309c..b4db7c45f 100644 --- a/geary-core/build.gradle.kts +++ b/geary-core/build.gradle.kts @@ -1,5 +1,3 @@ -import Com_mineinabyss_conventions_platform_gradle.Deps - plugins { id("geary.kotlin-conventions") kotlin("plugin.serialization") @@ -8,16 +6,15 @@ plugins { } dependencies { + implementation(gearylibs.fastutil) + implementation(libs.kotlin.reflect) { isTransitive = false } api(libs.koin.core) { isTransitive = false } //ecs-related libs implementation(gearylibs.bimap) { isTransitive = false } implementation(gearylibs.bitvector) - implementation(Deps.kotlin.reflect) { isTransitive = false } + compileOnly(libs.kotlinx.coroutines) - //provided by Minecraft - // TODO implementation here, avoid shading on papermc - compileOnly(gearylibs.fastutil) testImplementation(gearylibs.fastutil) testImplementation(libs.koin.test) testImplementation(libs.koin.test.junit5) diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/AccessorHolder.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/AccessorHolder.kt index e48deff13..c0bf4eb09 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/AccessorHolder.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/AccessorHolder.kt @@ -2,10 +2,12 @@ package com.mineinabyss.geary.ecs.accessors import com.mineinabyss.geary.ecs.accessors.building.AccessorBuilder import com.mineinabyss.geary.ecs.accessors.building.AccessorBuilderProvider +import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.systems.MutableAndSelector import com.mineinabyss.geary.ecs.engine.Archetype import com.mineinabyss.geary.ecs.query.AndSelector import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap +import org.koin.core.component.inject import kotlin.reflect.KProperty @@ -15,6 +17,8 @@ import kotlin.reflect.KProperty * @property family A lazily built immutable family that represents all data this holder needs to function. */ public open class AccessorHolder : MutableAndSelector(), AccessorBuilderProvider { + override val engine: Engine by inject() + public val family: AndSelector by lazy { build() } internal open val accessors = mutableListOf>() private val perArchetypeCache = Int2ObjectOpenHashMap>>() diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/building/AccessorBuilderProvider.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/building/AccessorBuilderProvider.kt index b36165b35..c2e6a3f17 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/building/AccessorBuilderProvider.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/accessors/building/AccessorBuilderProvider.kt @@ -5,17 +5,19 @@ import com.mineinabyss.geary.ecs.accessors.types.ComponentAccessor import com.mineinabyss.geary.ecs.accessors.types.ComponentOrDefaultAccessor import com.mineinabyss.geary.ecs.accessors.types.RelationWithDataAccessor import com.mineinabyss.geary.ecs.api.GearyComponent +import com.mineinabyss.geary.ecs.api.engine.EngineScope import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.relations.RelationValueId import com.mineinabyss.geary.ecs.engine.HOLDS_DATA import com.mineinabyss.geary.ecs.engine.withRole +import com.mineinabyss.idofront.typealiases.BukkitEntity import org.koin.core.component.KoinComponent import kotlin.reflect.typeOf /** * An empty interface that limits [AccessorBuilder] helper functions only to classes that use [Accessor]s. */ -public interface AccessorBuilderProvider: KoinComponent +public interface AccessorBuilderProvider : EngineScope, KoinComponent /** Gets a component, ensuring it is on the entity. */ public inline fun AccessorBuilderProvider.get(): AccessorBuilder> { diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/GearyType.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/GearyType.kt index f4c8a0fc4..d36341de2 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/GearyType.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/GearyType.kt @@ -63,5 +63,5 @@ public value class GearyType private constructor( override fun toString(): String = inner .map { (it.toULong().getComponentInfo()?.kClass as KClass<*>).simpleName ?: it } - .joinToString { ", " } + .joinToString(", ") } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/autoscan/AutoscanAnnotations.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/annotations/Handler.kt similarity index 62% rename from geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/autoscan/AutoscanAnnotations.kt rename to geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/annotations/Handler.kt index df8249663..e5d2f62e0 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/autoscan/AutoscanAnnotations.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/annotations/Handler.kt @@ -1,25 +1,10 @@ -package com.mineinabyss.geary.ecs.api.autoscan +package com.mineinabyss.geary.ecs.api.annotations import com.mineinabyss.geary.ecs.accessors.EventScope import com.mineinabyss.geary.ecs.accessors.SourceScope import com.mineinabyss.geary.ecs.accessors.TargetScope import com.mineinabyss.geary.ecs.api.systems.GearyListener -import com.mineinabyss.geary.ecs.api.systems.GearySystem -import com.mineinabyss.geary.ecs.api.systems.TickingSystem import com.mineinabyss.geary.ecs.events.handlers.GearyHandler -import com.mineinabyss.geary.ecs.query.Query - -/** - * Excludes this class from having its serializer automatically registered for component serialization - * with the AutoScanner. - */ -public annotation class ExcludeAutoScan - -/** - * Indicates this [GearySystem], such as [TickingSystem], [GearyListener], or [Query] be registered automatically - * on startup by the AutoScanner. - */ -public annotation class AutoScan /** * Indicates a function within a [GearyListener] should be registered as a [GearyHandler] @@ -40,3 +25,4 @@ public annotation class AutoScan */ @Target(AnnotationTarget.FUNCTION) public annotation class Handler + diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/Engine.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/Engine.kt index 67b102a11..b8df083d1 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/Engine.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/Engine.kt @@ -20,7 +20,9 @@ import kotlin.reflect.KClass * * Its companion object gets a service via Bukkit as its implementation. */ -public interface Engine: KoinComponent { +public interface Engine : KoinComponent, EngineScope { + override val engine: Engine get() = this + /** The root archetype representing a type of no components */ public val rootArchetype: Archetype @@ -68,7 +70,7 @@ public interface Engine: KoinComponent { public fun removeComponentFor(entity: GearyEntity, componentId: GearyComponentId): Boolean /** Removes an entity from the ECS, freeing up its entity id. */ - public fun removeEntity(entity: GearyEntity) + public fun removeEntity(entity: GearyEntity, callRemoveEvent: Boolean = true) /** Removes all components from an entity. */ public fun clearEntity(entity: GearyEntity) diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt index 5e327a522..c58f8cc69 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineHelpers.kt @@ -3,58 +3,59 @@ package com.mineinabyss.geary.ecs.api.engine import com.mineinabyss.geary.ecs.api.GearyComponentId import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.toGeary +import com.mineinabyss.geary.ecs.api.systems.GearySystem import com.mineinabyss.geary.ecs.components.ComponentInfo import com.mineinabyss.geary.ecs.serialization.Formats -import org.koin.core.component.KoinComponent -import org.koin.core.component.get -import org.koin.mp.KoinPlatformTools import kotlin.reflect.KClass import kotlin.reflect.KType /** Creates a new empty entity. May reuse recently deleted entity ids. */ -public fun KoinComponent.entity(): GearyEntity = get().newEntity() +public fun EngineScope.entity(): GearyEntity = engine.newEntity() /** @see entity */ -public inline fun KoinComponent.entity(run: GearyEntity.() -> Unit): GearyEntity = entity().apply(run) +public inline fun EngineScope.entity(run: GearyEntity.() -> Unit): GearyEntity = entity().apply(run) /** Creates a new empty entity that will get removed once [run] completes or fails. */ -public inline fun Engine.temporaryEntity(run: (GearyEntity) -> Unit) { - val entity = newEntity() +public inline fun EngineScope.temporaryEntity(callRemoveEvent: Boolean = false, run: (GearyEntity) -> Unit) { + val entity = entity() try { run(entity) } catch (e: Throwable) { e.printStackTrace() } finally { - entity.removeEntity() + entity.removeEntity(callRemoveEvent) } } -public inline fun KoinComponent.temporaryEntity(run: (GearyEntity) -> Unit) { - get().temporaryEntity(run) -} - /** Gets or registers the id of a component of type [T] */ -public inline fun KoinComponent.componentId(): GearyComponentId = componentId(T::class) +public inline fun EngineScope.componentId(): GearyComponentId = componentId(T::class) /** * Gets the id of a component by its serial name. * Throws an error if the component name does not exist. */ -public fun KoinComponent.componentId(serialName: String): GearyComponentId = +public fun EngineScope.componentId(serialName: String): GearyComponentId = componentId(Formats.getClassFor(serialName)) /** Gets or registers the id of a component by its [kType]. */ -public fun KoinComponent.componentId(kType: KType): GearyComponentId = componentId(kType.classifier as KClass<*>) +public fun EngineScope.componentId(kType: KType): GearyComponentId = + componentId(kType.classifier as KClass<*>) /** Gets or registers the id of a component by its [kClass]. */ -public fun KoinComponent.componentId(kClass: KClass<*>): GearyComponentId = get().getOrRegisterComponentIdForClass(kClass) +public fun EngineScope.componentId(kClass: KClass<*>): GearyComponentId = + engine.getOrRegisterComponentIdForClass(kClass) @Deprecated("Should not be getting an id for an id!", ReplaceWith("componentId(component)")) @Suppress("UNUSED_PARAMETER") -public fun KoinComponent.componentId(kClass: KClass): Nothing = error("Trying to access id for component id") +public fun EngineScope.componentId(kClass: KClass): Nothing = + error("Trying to access id for component id") /** Gets the [ComponentInfo] component from a component's id. */ public fun GearyComponentId.getComponentInfo(): ComponentInfo? = this.toGeary().get() -@Deprecated("This will be replaced with multi-receiver access in Kotlin 1.6.20") -public val globalEngine: Engine get() = KoinPlatformTools.defaultContext().get().get() +//@Deprecated("This will be replaced with multi-receiver access in Kotlin 1.6.20") +//public val globalEngine: Engine get() = KoinPlatformTools.defaultContext().get().get() + +public fun EngineScope.systems(vararg systems: GearySystem) { + systems.forEach { engine.addSystem(it) } +} diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineScope.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineScope.kt new file mode 100644 index 000000000..b6bcd2de2 --- /dev/null +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/engine/EngineScope.kt @@ -0,0 +1,7 @@ +package com.mineinabyss.geary.ecs.api.engine + +import org.koin.core.component.KoinComponent + +public interface EngineScope: KoinComponent { + public val engine: Engine +} diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt index cc2aad3a3..7b7651777 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt @@ -5,6 +5,7 @@ import com.mineinabyss.geary.ecs.api.GearyComponentId import com.mineinabyss.geary.ecs.api.GearyEntityId import com.mineinabyss.geary.ecs.api.GearyType import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.engine.EngineScope import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.engine.temporaryEntity import com.mineinabyss.geary.ecs.api.relations.Relation @@ -28,7 +29,9 @@ import org.koin.core.component.get as koinGet @Serializable @JvmInline @Suppress("NOTHING_TO_INLINE") -public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { +public value class GearyEntity(public val id: GearyEntityId) : EngineScope { + //TODO with multiple accessors, remove and require each functino call has scope + override val engine: Engine get() = koinGet() /** Gets the record associated with this entity or throws an error if it is no longer active on the koinGet(). */ public inline val record: Record get() = koinGet().getRecord(this) @@ -49,8 +52,8 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { }) /** Remove this entity from the ECS. */ - public fun removeEntity() { - koinGet().removeEntity(this) + public fun removeEntity(callRemoveEvent: Boolean = true) { + engine.removeEntity(this, callRemoveEvent) } /** @@ -63,7 +66,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { kClass: KClass = T::class, noEvent: Boolean = false ): T { - koinGet().setComponentFor(this, componentId(kClass), component, noEvent) + engine.setComponentFor(this, componentId(kClass), component, noEvent) return component } @@ -109,7 +112,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { valueClass: KClass<*> = value::class, noEvent: Boolean = false ) { - koinGet().setComponentFor(this, Relation.of(keyClass, valueClass).id, value, noEvent) + engine.setComponentFor(this, Relation.of(keyClass, valueClass).id, value, noEvent) } /** @@ -117,7 +120,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { * @param noEvent If true, will not fire an [AddedComponent] event. */ public fun setRelation(key: GearyComponentId, value: Any, noEvent: Boolean = false) { - koinGet().setComponentFor(this, Relation.of(key, componentId(value::class)).id, value, noEvent) + engine.setComponentFor(this, Relation.of(key, componentId(value::class)).id, value, noEvent) } /** Removes a relation key key of type [K] and value of type [V]. */ @@ -134,7 +137,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { /** Removes all relations with a value with id [componentId] on the entity. */ public fun removeRelationsByValue(componentId: GearyComponentId): Set { - val comps = koinGet().getRelationsFor(this, RelationValueId(componentId)) + val comps = engine.getRelationsFor(this, RelationValueId(componentId)) comps.forEach { (_, relation) -> removeRelation(relation) } @@ -147,7 +150,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { * @param noEvent If true, will not fire an [AddedComponent] event. */ public inline fun add(component: GearyComponentId, noEvent: Boolean = false) { - koinGet().addComponentFor(this, component, noEvent) + engine.addComponentFor(this, component, noEvent) } /** @@ -183,6 +186,13 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { return component } + /** Stops a given component on this entity from being persisted if it is already marked persistent. */ + public inline fun noPersist( + kClass: KClass = T::class, + ) { + removeRelation(Relation.of(kClass, PersistingComponent::class)) + } + @Deprecated("Likely unintentionally using list as a single component", ReplaceWith("setAllPersisting()")) public fun setPersisting(components: Collection): Collection = setPersisting(component = components) @@ -217,7 +227,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { /** Removes a component with id [component] from this entity. */ public inline fun remove(component: GearyComponentId): Boolean = - koinGet().removeComponentFor(this, component) + engine.removeComponentFor(this, component) /** * Removes a list of [components] from this entity. @@ -229,7 +239,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { /** Clears all components on this entity. */ public fun clear() { - koinGet().clearEntity(this) + engine.clearEntity(this) } /** Gets a component of type [T] on this entity. */ @@ -238,7 +248,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { /** Gets a [component] which holds data from this entity. Use [has] if the component is not to hold data. */ public inline fun get(component: GearyComponentId): GearyComponent? = - koinGet().getComponentFor(this, component) + engine.getComponentFor(this, component) /** Gets a component of type [T] or sets a [default] if no component was present. */ public inline fun getOrSet(kClass: KClass = T::class, default: () -> T): T = @@ -251,7 +261,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { ): T = get(kClass) ?: default().also { setPersisting(it, kClass) } /** Gets all the components on this entity, as well as relations in the form of [RelationComponent]. */ - public inline fun getComponents(): Set = koinGet().getComponentsFor(this) + public inline fun getComponents(): Set = engine.getComponentsFor(this) /** Gets the data in any relations on this entity with a value of type [T]. */ public inline fun getRelationsByValue(): Set = @@ -259,7 +269,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { /** Gets the data in any relations on this entity with the value [relationValueId]. */ public inline fun getRelationsByValue(relationValueId: RelationValueId): Set = - koinGet().getRelationsFor(this, relationValueId).mapTo(mutableSetOf()) { it.first } + engine.getRelationsFor(this, relationValueId).mapTo(mutableSetOf()) { it.first } /** Gets all persisting components on this entity. */ public inline fun getPersistingComponents(): Set = @@ -282,7 +292,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { /** Checks whether this entity has a [component], regardless of it holding data. */ public inline fun has(component: GearyComponentId): Boolean = - koinGet().hasComponentFor(this, component) + engine.hasComponentFor(this, component) /** * Checks whether an entity has all of [components] set or added. @@ -335,7 +345,7 @@ public value class GearyEntity(public val id: GearyEntityId) : KoinComponent { result: (event: GearyEntity) -> T, ): T { record.apply { - koinGet().temporaryEntity { event -> + engine.temporaryEntity(callRemoveEvent = false) { event -> init(event) archetype.callEvent(event, row, source) return result(event) diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/relations/Relation.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/relations/Relation.kt index 91c09ede5..502508af8 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/relations/Relation.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/relations/Relation.kt @@ -7,8 +7,8 @@ import com.mineinabyss.geary.ecs.engine.RELATION import com.mineinabyss.geary.ecs.engine.RELATION_KEY_MASK import com.mineinabyss.geary.ecs.engine.RELATION_VALUE_MASK import com.mineinabyss.geary.ecs.engine.isRelation +import com.mineinabyss.geary.ecs.helpers.GearyKoinComponent import kotlinx.serialization.Serializable -import org.koin.core.component.KoinComponent import kotlin.reflect.KClass /** @@ -39,7 +39,7 @@ public value class Relation private constructor( override fun toString(): String = "$key to $value" - public companion object: KoinComponent { + public companion object { public fun of( key: GearyComponentId, value: RelationValueId @@ -52,11 +52,13 @@ public value class Relation private constructor( public fun of(key: GearyComponentId, value: GearyComponentId): Relation = of(key, RelationValueId(value)) - public fun of(key: KClass<*>, value: KClass<*>): Relation = + public fun of(key: KClass<*>, value: KClass<*>): Relation = GearyKoinComponent { of(componentId(key), componentId(value)) + } - public inline fun of(): Relation = + public inline fun of(): Relation = GearyKoinComponent { of(componentId(), componentId()) + } /** * Creates a relation from an id that is assumed to be valid. Use this to avoid boxing Relation because of diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/FamilyBuilder.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/FamilyBuilder.kt index ecb5a1720..24f33bbdd 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/FamilyBuilder.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/FamilyBuilder.kt @@ -2,16 +2,27 @@ package com.mineinabyss.geary.ecs.api.systems import com.mineinabyss.geary.ecs.api.GearyComponent import com.mineinabyss.geary.ecs.api.GearyComponentId +import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.engine.EngineScope import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.relations.Relation import com.mineinabyss.geary.ecs.api.relations.RelationValueId import com.mineinabyss.geary.ecs.engine.* +import com.mineinabyss.geary.ecs.events.AddedComponent import com.mineinabyss.geary.ecs.query.* -import org.koin.core.component.KoinComponent +import org.koin.core.component.inject import kotlin.reflect.KType +import kotlin.reflect.typeOf -public abstract class FamilyBuilder { - public abstract fun build(): Family +public abstract class FamilyBuilder { + public fun build(): T { + preBuild() + return buildFamily() + } + + protected abstract fun buildFamily(): T + + protected open fun preBuild() {} public operator fun not(): MutableAndNotSelector = MutableAndNotSelector(mutableListOf(this)) } @@ -22,37 +33,47 @@ public fun family(init: MutableAndSelector.() -> Unit): AndSelector { public class MutableComponentLeaf( public var component: GearyComponentId -) : FamilyBuilder() { - override fun build(): ComponentLeaf = ComponentLeaf(component) +) : FamilyBuilder() { + override fun buildFamily(): ComponentLeaf = ComponentLeaf(component) } public class MutableRelationValueLeaf( public var relationValueId: RelationValueId, public val componentMustHoldData: Boolean = false -) : FamilyBuilder() { - override fun build(): RelationValueLeaf = RelationValueLeaf(relationValueId, componentMustHoldData) +) : FamilyBuilder() { + override fun buildFamily(): RelationValueLeaf = RelationValueLeaf(relationValueId, componentMustHoldData) } public class MutableRelationKeyLeaf( public var relationKeyId: GearyComponentId, public val componentMustHoldData: Boolean = false -) : FamilyBuilder() { - override fun build(): RelationKeyLeaf = RelationKeyLeaf(relationKeyId) +) : FamilyBuilder() { + override fun buildFamily(): RelationKeyLeaf = RelationKeyLeaf(relationKeyId) } -public abstract class MutableSelector : FamilyBuilder(), KoinComponent { - protected abstract val elements: MutableList +public abstract class MutableSelector : FamilyBuilder(), EngineScope { + override val engine: Engine by inject() + protected abstract val elements: MutableList> public val components: List get() = _components public val componentsWithData: List get() = _componentsWithData public val relationValueIds: List get() = _relationValueIds + public val onAdd: MutableSet = mutableSetOf() private val _components = mutableListOf() private val _componentsWithData = mutableListOf() private val _relationValueIds = mutableListOf() - protected fun add(element: FamilyBuilder) { + override fun preBuild() { + if (onAdd.isNotEmpty()) or { + this@MutableSelector.onAdd.forEach { + hasRelation(it, typeOf()) + } + } + } + + protected fun add(element: FamilyBuilder<*>) { elements += element if (element is MutableComponentLeaf) { val comp = element.component @@ -83,6 +104,7 @@ public abstract class MutableSelector : FamilyBuilder(), KoinComponent { has(componentId().withInvertedRole(HOLDS_DATA)) } } + public inline fun hasAdded() { has(componentId()) @@ -110,7 +132,7 @@ public abstract class MutableSelector : FamilyBuilder(), KoinComponent { when { relationKey != null && relationValue != null -> { - if(key.isMarkedNullable) or { + if (key.isMarkedNullable) or { hasRelation(Relation.of(relationKey.withRole(HOLDS_DATA), relationValue)) hasRelation(Relation.of(relationKey.withoutRole(HOLDS_DATA), relationValue)) } else @@ -138,24 +160,28 @@ public abstract class MutableSelector : FamilyBuilder(), KoinComponent { public fun hasRelation(relation: Relation) { has(relation.id) } + + public fun onAdded(id: GearyComponentId) { + onAdd += id + } } public open class MutableAndSelector( - override val elements: MutableList = mutableListOf() -) : MutableSelector() { - override fun build(): AndSelector = AndSelector(elements.build()) + override val elements: MutableList> = mutableListOf() +) : MutableSelector() { + override fun buildFamily(): AndSelector = AndSelector(elements.build()) } public class MutableAndNotSelector( - override val elements: MutableList = mutableListOf() -) : MutableSelector() { - override fun build(): AndNotSelector = AndNotSelector(elements.build()) + override val elements: MutableList> = mutableListOf() +) : MutableSelector() { + override fun buildFamily(): AndNotSelector = AndNotSelector(elements.build()) } public class MutableOrSelector( - override val elements: MutableList = mutableListOf() -) : MutableSelector() { - override fun build(): OrSelector = OrSelector(elements.build()) + override val elements: MutableList> = mutableListOf() +) : MutableSelector() { + override fun buildFamily(): OrSelector = OrSelector(elements.build()) } -private fun List.build() = map { it.build() } +private fun List>.build() = map { it.build() } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/GearyListener.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/GearyListener.kt index d45ea015c..93fadaee0 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/GearyListener.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/GearyListener.kt @@ -3,9 +3,15 @@ package com.mineinabyss.geary.ecs.api.systems import com.mineinabyss.geary.ecs.accessors.* import com.mineinabyss.geary.ecs.accessors.building.AccessorBuilder import com.mineinabyss.geary.ecs.accessors.building.AccessorBuilderProvider -import com.mineinabyss.geary.ecs.api.autoscan.Handler -import com.mineinabyss.geary.ecs.events.AddedComponent +import com.mineinabyss.geary.ecs.accessors.building.get +import com.mineinabyss.geary.ecs.accessors.types.ComponentAccessor +import com.mineinabyss.geary.ecs.api.GearyComponent +import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.engine.componentId +import com.mineinabyss.geary.ecs.engine.HOLDS_DATA +import com.mineinabyss.geary.ecs.engine.withRole import com.mineinabyss.geary.ecs.events.handlers.GearyHandler +import org.koin.core.component.inject import kotlin.reflect.KProperty import kotlin.reflect.full.extensionReceiverParameter import kotlin.reflect.typeOf @@ -19,6 +25,8 @@ import kotlin.reflect.typeOf * are the actual functions that run when a matching event is found. */ public abstract class GearyListener : GearySystem, AccessorBuilderProvider { + override val engine: Engine by inject() + public val source: AccessorHolder = AccessorHolder() public val target: AccessorHolder = AccessorHolder() public val event: AccessorHolder = AccessorHolder() @@ -48,11 +56,18 @@ public abstract class GearyListener : GearySystem, AccessorBuilderProvider { public operator fun Accessor.getValue(thisRef: EventScope, property: KProperty<*>): T = thisRef.data[index] as T + + /** Gets a component, ensuring it is on the entity. */ + public inline fun added(): AccessorBuilder> { + event.onAdded(componentId().withRole(HOLDS_DATA)) + return get() + } + //TODO allow checking that all components were added on source //TODO an Accessor which returns the specific component added. - public fun allAdded() { - event.or { - target.family.components.forEach { hasRelation(it, typeOf()) } + public fun AccessorHolder.allAdded() { + family.components.forEach { + event.onAdded(it) } } } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt index 3c029f1b8..7c530f320 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/systems/QueryManager.kt @@ -3,7 +3,7 @@ package com.mineinabyss.geary.ecs.api.systems import com.mineinabyss.geary.ecs.accessors.EventScope import com.mineinabyss.geary.ecs.accessors.SourceScope import com.mineinabyss.geary.ecs.accessors.TargetScope -import com.mineinabyss.geary.ecs.api.autoscan.Handler +import com.mineinabyss.geary.ecs.api.annotations.Handler import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.toGeary diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt index 45308d14e..965a08532 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt @@ -16,6 +16,9 @@ import com.mineinabyss.geary.ecs.query.Query import com.mineinabyss.geary.ecs.query.contains import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap +import it.unimi.dsi.fastutil.longs.LongArrayList +import kotlinx.coroutines.newSingleThreadContext +import kotlinx.coroutines.sync.Mutex import org.koin.core.component.KoinComponent import org.koin.core.component.inject import java.util.* @@ -35,7 +38,7 @@ public data class Archetype( /** The entity ids in this archetype. Indices are the same as [componentData]'s sub-lists. */ //TODO aim to make private - internal val ids = mutableListOf() + internal val ids: LongArrayList = LongArrayList() /** Component ids in the type that are to hold data */ // Currently all relations must hold data and the HOLDS_DATA bit on them corresponds to the component part. @@ -122,12 +125,11 @@ public data class Archetype( public operator fun get(row: Int, componentId: GearyComponentId): GearyComponent? { val compIndex = indexOf(componentId) if (compIndex == -1) return null - return componentData[compIndex][row] } /** @return The entity stored at a given [row] in this archetype. */ - internal fun getEntity(row: Int): GearyEntity = ids.get(row).toGeary() + internal fun getEntity(row: Int): GearyEntity = ids.getLong(row).toGeary() /** @return Whether this archetype has a [componentId] in its type, regardless of the [HOLDS_DATA] role. */ public operator fun contains(componentId: GearyComponentId): Boolean = @@ -239,10 +241,13 @@ public data class Archetype( val moveTo = this + dataComponent val newCompIndex = moveTo.dataHoldingType.indexOf(dataComponent) val componentData = getComponents(row).apply { + //TODO this will throw an error if row changed when something else removed the entity from here. + // For now we try to move it as early as possible :s + removeEntity(row) add(newCompIndex, data) } - return moveTo.addEntityWithData(entity, componentData).also { removeEntity(row) } + return moveTo.addEntityWithData(entity, componentData) } /** @@ -284,7 +289,7 @@ public data class Archetype( internal fun removeEntity(row: Int) { try { val lastIndex = ids.lastIndex - val replacement = ids.get(lastIndex) + val replacement = ids.getLong(lastIndex) ids[row] = replacement if (lastIndex != row) diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt index c735f70ff..003a234a7 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/GearyEngine.kt @@ -18,6 +18,7 @@ import com.mineinabyss.geary.ecs.components.RelationComponent import com.mineinabyss.geary.ecs.entities.parents import com.mineinabyss.geary.ecs.entities.removeParent import com.mineinabyss.geary.ecs.events.AddedComponent +import com.mineinabyss.geary.ecs.events.EntityRemoved import com.mineinabyss.idofront.messaging.logError import com.mineinabyss.idofront.time.inWholeTicks import org.koin.core.component.inject @@ -46,6 +47,7 @@ public open class GearyEngine : TickingEngine() { classToComponentMap[ComponentInfo::class] = componentInfo.id } + override fun start(): Boolean { return super.start().also { if (it) { @@ -194,12 +196,14 @@ public open class GearyEngine : TickingEngine() { override fun hasComponentFor(entity: GearyEntity, componentId: GearyComponentId): Boolean = getRecord(entity).archetype.contains(componentId) - override fun removeEntity(entity: GearyEntity) { + override fun removeEntity(entity: GearyEntity, callRemoveEvent: Boolean) { + if (callRemoveEvent) + entity.callEvent(EntityRemoved()) // remove all children of this entity from the ECS as well entity.apply { children.forEach { // Remove self from the child's parents or remove the child if it no longer has parents - if (parents == setOf(this)) it.removeEntity() + if (parents == setOf(this)) it.removeEntity(callRemoveEvent) else it.removeParent(this) } } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Record.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Record.kt index 32383070e..d28b8d750 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Record.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Record.kt @@ -1,11 +1,16 @@ package com.mineinabyss.geary.ecs.engine -import com.mineinabyss.geary.ecs.api.engine.globalEngine +import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.engine.EngineScope +import org.koin.core.component.get @JvmInline -public value class Record(public val id: Long) { +public value class Record(public val id: Long) : EngineScope { + //TODO multiple receivers + override val engine: Engine get() = get() + //Upper 32 bits are row id - public val archetype: Archetype get() = globalEngine.getArchetype((id shr 32).toInt()) + public val archetype: Archetype get() = engine.getArchetype((id shr 32).toInt()) //Lower 32 bits are row id public val row: Int get() = id.toInt() diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TypeRoles.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TypeRoles.kt index b44e5b4a8..20bce3798 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TypeRoles.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/TypeRoles.kt @@ -23,10 +23,10 @@ public const val ENTITY_MASK: ULong = 0x00FFFFFFFFFFFFFFuL public const val RELATION_VALUE_MASK: ULong = 0x00FFFFFF00000000uL public const val RELATION_KEY_MASK: ULong = 0xFF000000FFFFFFFFuL -public fun GearyComponentId.isInstance(): Boolean = this.hasRole(INSTANCEOF) -public fun GearyComponentId.isChild(): Boolean = this.hasRole(CHILDOF) -public fun GearyComponentId.isRelation(): Boolean = this.hasRole(RELATION) -public fun GearyComponentId.holdsData(): Boolean = this.hasRole(HOLDS_DATA) +public inline fun GearyComponentId.isInstance(): Boolean = this.hasRole(INSTANCEOF) +public inline fun GearyComponentId.isChild(): Boolean = this.hasRole(CHILDOF) +public inline fun GearyComponentId.isRelation(): Boolean = this.hasRole(RELATION) +public inline fun GearyComponentId.holdsData(): Boolean = this.hasRole(HOLDS_DATA) public inline fun GearyComponentId.hasRole(role: ULong): Boolean = this and role != 0uL diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/RegenerateUUIDOnClash.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/RegenerateUUIDOnClash.kt new file mode 100644 index 000000000..3c57df7f9 --- /dev/null +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/RegenerateUUIDOnClash.kt @@ -0,0 +1,3 @@ +package com.mineinabyss.geary.ecs.entities + +public object RegenerateUUIDOnClash diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/UUID2GearyMap.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/UUID2GearyMap.kt new file mode 100644 index 000000000..69438f7a2 --- /dev/null +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/entities/UUID2GearyMap.kt @@ -0,0 +1,62 @@ +package com.mineinabyss.geary.ecs.entities + +import com.mineinabyss.geary.ecs.accessors.TargetScope +import com.mineinabyss.geary.ecs.accessors.building.get +import com.mineinabyss.geary.ecs.api.annotations.Handler +import com.mineinabyss.geary.ecs.api.entities.GearyEntity +import com.mineinabyss.geary.ecs.api.entities.toGeary +import com.mineinabyss.geary.ecs.api.systems.GearyListener +import com.mineinabyss.geary.ecs.events.EntityRemoved +import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap +import java.util.* + +public class UUID2GearyMap : GearyListener() { + private val uuid2geary = Object2LongOpenHashMap().apply { + defaultReturnValue(-1) + } + + public operator fun get(uuid: UUID): GearyEntity? = + uuid2geary.getLong(uuid).takeIf { it != -1L }?.toGeary() + + public operator fun set(uuid: UUID, entity: GearyEntity): GearyEntity = + uuid2geary.put(uuid, entity.id.toLong()).toGeary() + + public operator fun contains(uuid: UUID): Boolean = uuid2geary.containsKey(uuid) + + public fun remove(uuid: UUID): GearyEntity? = + uuid2geary.removeLong(uuid).takeIf { it != -1L }?.toGeary() + + public fun startTracking() { + engine.addSystem(TrackUUIDOnAdd()) + engine.addSystem(UnTrackUUIDOnRemove()) + } + + public inner class TrackUUIDOnAdd : GearyListener() { + private val TargetScope.uuid by added() + + @Handler + private fun TargetScope.track() { + if (contains(uuid)) + if (entity.has()) { + val newUUID = UUID.randomUUID() + entity.set(newUUID) + set(newUUID, entity) + } else error("Tried tracking entity $entity with already existing uuid $uuid") + else + set(uuid, entity) + } + } + + public inner class UnTrackUUIDOnRemove : GearyListener() { + private val TargetScope.uuid by get() + + init { + event.has() + } + + @Handler + private fun TargetScope.untrack() { + remove(uuid) + } + } +} diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/events/EntityRemoved.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/events/EntityRemoved.kt new file mode 100644 index 000000000..563adb6fb --- /dev/null +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/events/EntityRemoved.kt @@ -0,0 +1,3 @@ +package com.mineinabyss.geary.ecs.events + +public class EntityRemoved diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/helpers/GearyKoinComponent.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/helpers/GearyKoinComponent.kt index f84c3487b..c53f1a6fd 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/helpers/GearyKoinComponent.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/helpers/GearyKoinComponent.kt @@ -1,11 +1,17 @@ package com.mineinabyss.geary.ecs.helpers import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.engine.EngineScope import com.mineinabyss.geary.ecs.api.systems.QueryManager -import org.koin.core.component.KoinComponent import org.koin.core.component.inject -public open class GearyKoinComponent: KoinComponent { - public val engine: Engine by inject() +public open class GearyKoinComponent : EngineScope { + public override val engine: Engine by inject() public val queryManager: QueryManager by inject() + + public companion object { + public inline operator fun invoke(run: GearyKoinComponent.() -> T): T { + return GearyKoinComponent().run(run) + } + } } diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializer.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializer.kt index a9cd9ed0b..ec9009a88 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializer.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/serialization/GearyEntitySerializer.kt @@ -1,6 +1,8 @@ package com.mineinabyss.geary.ecs.serialization import com.mineinabyss.geary.ecs.api.GearyComponent +import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.engine.EngineScope import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.entities.GearyEntity @@ -13,12 +15,14 @@ import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import org.koin.core.component.KoinComponent +import org.koin.core.component.inject /** * A serializer which loads a new entity from a list of components. */ -public object GearyEntitySerializer : KSerializer, KoinComponent { +public object GearyEntitySerializer : KSerializer, EngineScope { + override val engine: Engine by inject() + public val componentListSerializer: KSerializer> = ListSerializer(PolymorphicSerializer(GearyComponent::class)) override val descriptor: SerialDescriptor = componentListSerializer.descriptor diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/systems/QueryManagerTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/systems/QueryManagerTest.kt index 1c3615c37..4acbb3ac9 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/systems/QueryManagerTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/api/systems/QueryManagerTest.kt @@ -4,7 +4,7 @@ import com.mineinabyss.geary.ecs.accessors.TargetScope import com.mineinabyss.geary.ecs.accessors.building.get import com.mineinabyss.geary.ecs.accessors.building.relation import com.mineinabyss.geary.ecs.api.GearyType -import com.mineinabyss.geary.ecs.api.autoscan.Handler +import com.mineinabyss.geary.ecs.api.annotations.Handler import com.mineinabyss.geary.ecs.api.engine.componentId import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.relations.RelationValueId diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/ComponentAddEventKtTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/ComponentAddEventKtTest.kt index 9b25ef6e8..7c8b00f4b 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/ComponentAddEventKtTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/ComponentAddEventKtTest.kt @@ -2,7 +2,7 @@ package com.mineinabyss.geary.ecs.events import com.mineinabyss.geary.ecs.accessors.TargetScope import com.mineinabyss.geary.ecs.accessors.building.get -import com.mineinabyss.geary.ecs.api.autoscan.Handler +import com.mineinabyss.geary.ecs.api.annotations.Handler import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.systems.GearyListener import com.mineinabyss.geary.ecs.engine.getArchetype @@ -16,13 +16,9 @@ internal class ComponentAddEventKtTest : GearyTest() { //TODO write test for all methods of checking for added inner class OnStringAdd : GearyListener() { // All three get added - val TargetScope.string by get() - val TargetScope.int by get() - val TargetScope.double by get() - - init { - allAdded() - } + val TargetScope.string by added() + val TargetScope.int by added() + val TargetScope.double by added() @Handler fun increment() { diff --git a/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/SourceTargetEventTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/SourceTargetEventTest.kt index 0c6875e31..a3e161ebc 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/SourceTargetEventTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/ecs/events/SourceTargetEventTest.kt @@ -4,7 +4,7 @@ import com.mineinabyss.geary.ecs.accessors.EventScope import com.mineinabyss.geary.ecs.accessors.SourceScope import com.mineinabyss.geary.ecs.accessors.TargetScope import com.mineinabyss.geary.ecs.accessors.building.get -import com.mineinabyss.geary.ecs.api.autoscan.Handler +import com.mineinabyss.geary.ecs.api.annotations.Handler import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.systems.GearyListener import com.mineinabyss.geary.helpers.GearyTest diff --git a/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt b/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt index 177075e9c..f0f995f7f 100644 --- a/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt +++ b/geary-core/src/test/java/com/mineinabyss/geary/helpers/GearyTest.kt @@ -1,6 +1,7 @@ package com.mineinabyss.geary.helpers import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.engine.EngineScope import com.mineinabyss.geary.ecs.api.systems.QueryManager import com.mineinabyss.geary.ecs.engine.GearyEngine import org.junit.jupiter.api.AfterAll @@ -10,8 +11,8 @@ import org.koin.dsl.module import org.koin.test.KoinTest import org.koin.test.get -abstract class GearyTest : KoinTest { - val engine get() = get() +abstract class GearyTest : KoinTest, EngineScope { + override val engine get() = get() val queryManager get() = get() init { diff --git a/geary-prefabs/build.gradle.kts b/geary-prefabs/build.gradle.kts index de17005c3..50b765f27 100644 --- a/geary-prefabs/build.gradle.kts +++ b/geary-prefabs/build.gradle.kts @@ -10,4 +10,5 @@ dependencies { compileOnly(gearylibs.fastutil) compileOnly(project(":geary-core")) + compileOnly(project(":geary-autoscan")) } diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabKey.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabKey.kt index 80b108828..7697334ef 100644 --- a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabKey.kt +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabKey.kt @@ -3,6 +3,8 @@ package com.mineinabyss.geary.prefabs import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.prefabs.serializers.PrefabKeySerializer import kotlinx.serialization.Serializable +import org.koin.core.component.KoinComponent +import org.koin.core.component.get /** * An inline class which represents a key build from a [namespace] and [name], separated @@ -10,11 +12,14 @@ import kotlinx.serialization.Serializable */ @Serializable(with = PrefabKeySerializer::class) @JvmInline -public value class PrefabKey private constructor(public val key: String) { +public value class PrefabKey private constructor(public val key: String) : KoinComponent { public val namespace: String get() = key.substringBefore(':') public val name: String get() = key.substringAfter(':') - public fun toEntity(): GearyEntity? = PrefabManager[this] + //TODO multiple receivers + private val prefabManager: PrefabManager get() = get() + + public fun toEntity(): GearyEntity? = prefabManager[this] override fun toString(): String = "$namespace:$name" diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManager.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManager.kt index cd9fc6228..b780c8a38 100644 --- a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManager.kt +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManager.kt @@ -1,17 +1,18 @@ package com.mineinabyss.geary.prefabs +import com.mineinabyss.geary.ecs.api.engine.Engine +import com.mineinabyss.geary.ecs.api.engine.EngineScope import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.with import com.mineinabyss.geary.ecs.api.relations.NoInherit import com.mineinabyss.geary.ecs.serialization.Formats import com.mineinabyss.geary.ecs.serialization.GearyEntitySerializer -import com.mineinabyss.geary.prefabs.PrefabManager.keys import com.mineinabyss.geary.prefabs.configuration.components.Prefab +import com.mineinabyss.geary.prefabs.helpers.inheritPrefabs import com.mineinabyss.idofront.messaging.logError import com.uchuhimo.collections.MutableBiMap import com.uchuhimo.collections.mutableBiMapOf -import org.koin.core.component.KoinComponent import java.io.File /** @@ -19,7 +20,9 @@ import java.io.File * * @property keys A list of registered [PrefabKey]s. */ -public object PrefabManager: KoinComponent { +public class PrefabManager( + override val engine: Engine +) : EngineScope { public val keys: List get() = prefabs.keys.toList() private val prefabs: MutableBiMap = mutableBiMapOf() diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManagerScope.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManagerScope.kt new file mode 100644 index 000000000..800864b9a --- /dev/null +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/PrefabManagerScope.kt @@ -0,0 +1,14 @@ +package com.mineinabyss.geary.prefabs + +import org.koin.core.component.KoinComponent +import org.koin.core.component.get + +public interface PrefabManagerScope : KoinComponent { + public val prefabManager: PrefabManager + + public companion object { + public inline fun run(run: PrefabManagerScope.() -> T): T = object : PrefabManagerScope { + override val prefabManager: PrefabManager = get() + }.run(run) + } +} diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseChildOnPrefab.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseChildOnPrefab.kt index 95d5e1479..202140953 100644 --- a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseChildOnPrefab.kt +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseChildOnPrefab.kt @@ -2,8 +2,8 @@ package com.mineinabyss.geary.prefabs.configuration.systems import com.mineinabyss.geary.ecs.accessors.TargetScope import com.mineinabyss.geary.ecs.accessors.building.get -import com.mineinabyss.geary.ecs.api.autoscan.AutoScan -import com.mineinabyss.geary.ecs.api.autoscan.Handler +import com.mineinabyss.geary.autoscan.AutoScan +import com.mineinabyss.geary.ecs.api.annotations.Handler import com.mineinabyss.geary.ecs.api.engine.entity import com.mineinabyss.geary.ecs.api.systems.GearyListener import com.mineinabyss.geary.ecs.components.EntityName @@ -13,11 +13,7 @@ import com.mineinabyss.geary.prefabs.configuration.components.ChildrenOnPrefab @AutoScan public class ParseChildOnPrefab : GearyListener() { - private val TargetScope.child by get() - - init { - allAdded() - } + private val TargetScope.child by added() @Handler private fun TargetScope.convertToRelation() { @@ -31,11 +27,7 @@ public class ParseChildOnPrefab : GearyListener() { @AutoScan public class ParseChildrenOnPrefab : GearyListener() { - private val TargetScope.children by get() - - init { - allAdded() - } + private val TargetScope.children by added() @Handler private fun TargetScope.convertToRelation() { diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseRelationComponent.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseRelationComponent.kt index e46b07aab..2e2ee8cfa 100644 --- a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseRelationComponent.kt +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseRelationComponent.kt @@ -2,18 +2,14 @@ package com.mineinabyss.geary.prefabs.configuration.systems import com.mineinabyss.geary.ecs.accessors.TargetScope import com.mineinabyss.geary.ecs.accessors.building.get -import com.mineinabyss.geary.ecs.api.autoscan.AutoScan -import com.mineinabyss.geary.ecs.api.autoscan.Handler +import com.mineinabyss.geary.autoscan.AutoScan +import com.mineinabyss.geary.ecs.api.annotations.Handler import com.mineinabyss.geary.ecs.api.systems.GearyListener import com.mineinabyss.geary.ecs.components.RelationComponent @AutoScan public class ParseRelationComponent : GearyListener() { - private val TargetScope.relation by get() - - init { - allAdded() - } + private val TargetScope.relation by added() @Handler private fun TargetScope.convertToRelation() { diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseRelationOnPrefab.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseRelationOnPrefab.kt index 9b9f67515..a4aefa90d 100644 --- a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseRelationOnPrefab.kt +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/configuration/systems/ParseRelationOnPrefab.kt @@ -2,19 +2,15 @@ package com.mineinabyss.geary.prefabs.configuration.systems import com.mineinabyss.geary.ecs.accessors.TargetScope import com.mineinabyss.geary.ecs.accessors.building.get -import com.mineinabyss.geary.ecs.api.autoscan.AutoScan -import com.mineinabyss.geary.ecs.api.autoscan.Handler +import com.mineinabyss.geary.autoscan.AutoScan +import com.mineinabyss.geary.ecs.api.annotations.Handler import com.mineinabyss.geary.ecs.api.systems.GearyListener import com.mineinabyss.geary.ecs.serialization.parseEntity import com.mineinabyss.geary.prefabs.configuration.components.RelationOnPrefab @AutoScan public class ParseRelationOnPrefab : GearyListener() { - private val TargetScope.relation by get() - - init { - allAdded() - } + private val TargetScope.relation by added() @Handler private fun TargetScope.convertToRelation() { diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/events/PrefabLoaded.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/events/PrefabLoaded.kt new file mode 100644 index 000000000..741576d66 --- /dev/null +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/events/PrefabLoaded.kt @@ -0,0 +1,3 @@ +package com.mineinabyss.geary.prefabs.events + +public class PrefabLoaded diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/helpers/InheritPrefabs.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/helpers/InheritPrefabs.kt index e11b0e7ce..9191f2b25 100644 --- a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/helpers/InheritPrefabs.kt +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/helpers/InheritPrefabs.kt @@ -1,8 +1,8 @@ -package com.mineinabyss.geary.prefabs +package com.mineinabyss.geary.prefabs.helpers import com.mineinabyss.geary.ecs.api.entities.GearyEntity +import com.mineinabyss.geary.prefabs.PrefabKey import com.mineinabyss.geary.prefabs.configuration.components.InheritPrefabs -import com.mineinabyss.geary.prefabs.helpers.addPrefab /** * Adds prefabs to this entity from an [InheritPrefabs] component. Will make sure parents have their prefabs diff --git a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/serializers/PrefabByReferenceSerializer.kt b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/serializers/PrefabByReferenceSerializer.kt index b47d5d88c..ea448fc56 100644 --- a/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/serializers/PrefabByReferenceSerializer.kt +++ b/geary-prefabs/src/main/kotlin/com/mineinabyss/geary/prefabs/serializers/PrefabByReferenceSerializer.kt @@ -4,23 +4,26 @@ import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.serialization.DescriptorWrapper import com.mineinabyss.geary.prefabs.PrefabKey import com.mineinabyss.geary.prefabs.PrefabManager +import com.mineinabyss.geary.prefabs.PrefabManagerScope import kotlinx.serialization.KSerializer import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder +import org.koin.core.component.inject /** * Allows us to serialize entity types to a reference to ones actually registered in the system. * This is used to load the static entity type when we decode components from an in-game entity. */ @Deprecated("This will not work properly until ktx.serialization fully supports inline classes") -public object PrefabByReferenceSerializer : KSerializer { +public object PrefabByReferenceSerializer : KSerializer, PrefabManagerScope { + override val prefabManager: PrefabManager by inject() override val descriptor: SerialDescriptor = DescriptorWrapper("geary:prefab", PrefabKey.serializer().descriptor) @Suppress("UNCHECKED_CAST") override fun deserialize(decoder: Decoder): GearyEntity { val prefabKey = decoder.decodeSerializableValue(PrefabKey.serializer()) - return (PrefabManager[prefabKey] ?: error("Error deserializing, $prefabKey is not a registered prefab")) + return (prefabManager[prefabKey] ?: error("Error deserializing, $prefabKey is not a registered prefab")) } override fun serialize(encoder: Encoder, value: GearyEntity) { diff --git a/geary-web-console/build.gradle.kts b/geary-web-console/build.gradle.kts index d97b7d2b9..11c5c5837 100644 --- a/geary-web-console/build.gradle.kts +++ b/geary-web-console/build.gradle.kts @@ -6,7 +6,6 @@ plugins { java kotlin("multiplatform") kotlin("plugin.serialization") - id("com.mineinabyss.conventions.platform") // id("com.mineinabyss.conventions.publication") // id("com.mineinabyss.conventions.testing") id("org.jetbrains.compose") version "1.0.1" @@ -50,13 +49,13 @@ kotlin { dependencies { compileOnly("io.papermc.paper:paper-api:$serverVersion") compileOnly(project(":geary-core")) + compileOnly(project(":geary-papermc-core")) compileOnly(libs.kotlin.stdlib) compileOnly(libs.ktor.serialization) compileOnly(libs.ktor.server.core) compileOnly(libs.ktor.server.netty) compileOnly(libs.logback.classic) compileOnly(libs.kmongo.coroutine.serialization) - compileOnly(project(":geary-platform-papermc")) } } diff --git a/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt b/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt index 1a0e25394..bf010629f 100644 --- a/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt +++ b/geary-web-console/src/jvmMain/kotlin/com/mineinabyss/geary/webconsole/GearyWebConsole.kt @@ -4,7 +4,7 @@ import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.toGeary import com.mineinabyss.geary.ecs.helpers.listComponents import com.mineinabyss.geary.ecs.helpers.GearyKoinComponent -import com.mineinabyss.geary.minecraft.access.toGeary +import com.mineinabyss.geary.papermc.access.toGeary import com.mineinabyss.geary.webconsole.data.EntityInfo import io.ktor.application.* import io.ktor.features.* diff --git a/platforms/geary-platform-papermc/core/build.gradle.kts b/platforms/geary-platform-papermc/core/build.gradle.kts deleted file mode 100644 index 5ff3abedb..000000000 --- a/platforms/geary-platform-papermc/core/build.gradle.kts +++ /dev/null @@ -1,8 +0,0 @@ -plugins { - id("geary.kotlin-conventions") - kotlin("plugin.serialization") -} - -repositories { - maven("https://raw.githubusercontent.com/TheBlackEntity/PlugMan/repository/") -} diff --git a/platforms/geary-platform-papermc/plugin/build.gradle.kts b/platforms/geary-platform-papermc/plugin/build.gradle.kts deleted file mode 100644 index b09b1e666..000000000 --- a/platforms/geary-platform-papermc/plugin/build.gradle.kts +++ /dev/null @@ -1,30 +0,0 @@ -plugins { - id("geary.kotlin-conventions") - id("com.mineinabyss.conventions.papermc") - id("com.mineinabyss.conventions.publication") - id("com.mineinabyss.conventions.copyjar") - kotlin("plugin.serialization") -} - -configurations { - runtimeClasspath { - exclude(group = "io.insert-koin", module = "koin-core") - } -} -repositories { - maven("https://raw.githubusercontent.com/TheBlackEntity/PlugMan/repository/") -} - -dependencies { - // Shaded - implementation(project(":geary-platform-papermc")) - implementation(project(":geary-web-console")) - - // Other plugins - compileOnly(gearylibs.plugman) -} -tasks { - shadowJar { - archiveBaseName.set("Geary") - } -} diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt deleted file mode 100644 index e1b6cf4a3..000000000 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/GearyPlugin.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.mineinabyss.geary.minecraft - -import com.mineinabyss.geary.ecs.helpers.GearyKoinComponent -import org.bukkit.plugin.java.JavaPlugin -import org.koin.core.component.get - -public abstract class GearyPlugin: JavaPlugin() - -public val GearyKoinComponent.plugin: GearyPlugin get() = get() diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitAssociations.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitAssociations.kt deleted file mode 100644 index 95aff3cc6..000000000 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitAssociations.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.mineinabyss.geary.minecraft.access - -import com.mineinabyss.geary.ecs.api.entities.GearyEntity -import com.mineinabyss.geary.ecs.api.entities.toGeary -import com.mineinabyss.geary.minecraft.events.GearyEntityRemoveEvent -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap -import org.bukkit.event.EventHandler -import org.bukkit.event.EventPriority -import org.bukkit.event.Listener -import java.util.* -import kotlin.collections.set - -public object BukkitAssociations : Listener { - private val entityMap = Object2LongOpenHashMap() - - public operator fun get(uuid: UUID): GearyEntity? { - return (entityMap.getOrDefault(uuid, null) ?: return null).toGeary() - } - - public operator fun contains(uuid: UUID): Boolean = entityMap.containsKey(uuid) - - public fun register(uuid: UUID, entity: GearyEntity) { - entityMap[uuid] = entity.id.toLong() - } - - public fun remove(uuid: UUID): GearyEntity? { - if (uuid !in entityMap) return null - return entityMap.removeLong(uuid).toGeary() - } - - public inline fun getOrPut(uuid: UUID, run: () -> GearyEntity): GearyEntity { - //if the entity is already registered, return it - get(uuid)?.let { return it } - val entity = run() - register(uuid, entity) - return entity - } - - @EventHandler(priority = EventPriority.LOWEST) - public fun GearyEntityRemoveEvent.onEntityRemoved() { - entity.get()?.let { remove(it) } - } -} diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityAssociations.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityAssociations.kt deleted file mode 100644 index e2b532775..000000000 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityAssociations.kt +++ /dev/null @@ -1,131 +0,0 @@ -package com.mineinabyss.geary.minecraft.access - -import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent -import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent -import com.destroystokyo.paper.event.player.PlayerPostRespawnEvent -import com.mineinabyss.geary.ecs.api.GearyComponent -import com.mineinabyss.geary.ecs.api.engine.entity -import com.mineinabyss.geary.ecs.api.entities.GearyEntity -import com.mineinabyss.geary.minecraft.events.GearyEntityRemoveEvent -import com.mineinabyss.geary.minecraft.hasComponentsEncoded -import com.mineinabyss.geary.minecraft.store.decodeComponentsFrom -import com.mineinabyss.geary.minecraft.store.encodeComponentsTo -import com.mineinabyss.idofront.typealiases.BukkitEntity -import org.bukkit.entity.Entity -import org.bukkit.entity.Player -import org.bukkit.event.EventHandler -import org.bukkit.event.EventPriority -import org.bukkit.event.Listener -import org.bukkit.event.player.PlayerJoinEvent -import org.bukkit.event.player.PlayerQuitEvent -import org.koin.core.component.KoinComponent - -internal typealias OnEntityRegister = GearyEntity.(Entity) -> Unit -internal typealias OnEntityUnregister = GearyEntity.(Entity) -> Unit - -public object BukkitEntityAssociations : Listener, KoinComponent { - //TODO this should be done through events - private val onBukkitEntityRegister: MutableList = mutableListOf() - private val onBukkitEntityUnregister: MutableList = mutableListOf() - - public fun onBukkitEntityRegister(add: OnEntityRegister) { - onBukkitEntityRegister.add(add) - } - - public fun onBukkitEntityUnregister(add: OnEntityUnregister) { - onBukkitEntityUnregister.add(add) - } - - public fun registerEntity(entity: Entity): GearyEntity { - val uuid = entity.uniqueId - BukkitAssociations[uuid]?.let { return it } - - val gearyEntity = entity() - - gearyEntity.apply { - setAll( - onBukkitEntityRegister.flatMap { mapping -> - mutableListOf().apply { mapping(entity) } - } - ) - - BukkitAssociations.register(uuid, gearyEntity) - - val pdc = entity.persistentDataContainer - if (pdc.hasComponentsEncoded) - gearyEntity.decodeComponentsFrom(pdc) - // allow us to both get the BukkitEntity and specific class (ex Player) - entity.type.entityClass?.kotlin?.let { bukkitClass -> - set(entity, bukkitClass) - } - - // Any component addition listener that wants Bukkit entity will immediately - // run, so we do this last. Potentially change how that fires in the future. - set(entity) - } - - return gearyEntity - } - - private fun unregisterEntity(entity: Entity): GearyEntity? { - val gearyEntity = BukkitAssociations[entity.uniqueId] ?: return null - - for (extension in onBukkitEntityUnregister) { - extension(gearyEntity, entity) - } - - val pdc = entity.persistentDataContainer - gearyEntity.encodeComponentsTo(pdc) - - return BukkitAssociations.remove(entity.uniqueId) - } - - - @EventHandler(priority = EventPriority.LOWEST) - public fun GearyEntityRemoveEvent.onEntityRemoved() { - entity.get()?.let { - unregisterEntity(it) - } - } - - @EventHandler(priority = EventPriority.LOWEST) - public fun PlayerJoinEvent.onPlayerLogin() { - registerEntity(player) - } - - @EventHandler(priority = EventPriority.LOWEST) - public fun PlayerQuitEvent.onPlayerLogout() { - removeEntityAndEncodeComponents(player) - } - - /** Remove entities from ECS when they are removed from Bukkit for any reason (Uses PaperMC event) */ - @EventHandler(priority = EventPriority.LOWEST) - public fun EntityAddToWorldEvent.onBukkitEntityAdd() { - // Only remove player from ECS on disconnect, not death - if (entity is Player) return - registerEntity(entity) - } - - /** Remove entities from ECS when they are removed from Bukkit for any reason (Uses PaperMC event) */ - @EventHandler(priority = EventPriority.HIGHEST) - public fun EntityRemoveFromWorldEvent.onBukkitEntityRemove() { - // Only remove player from ECS on disconnect, not death - if (entity is Player) return - removeEntityAndEncodeComponents(entity) - } - - public fun removeEntityAndEncodeComponents(entity: BukkitEntity) { - val gearyEntity = entity.toGearyOrNull() ?: return - //TODO some way of knowing if this entity is permanently removed - gearyEntity.encodeComponentsTo(entity) - unregisterEntity(entity) - gearyEntity.removeEntity() - } - - /** Player death counts as an entity being removed from the world so we should add them back after respawn */ - @EventHandler(priority = EventPriority.LOWEST) - public fun PlayerPostRespawnEvent.onPlayerRespawn() { - //TODO add Dead component on death and remove it here - // Or should we add an inactive component that prevents systems from iterating over dead players? - } -} diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityConversion.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityConversion.kt deleted file mode 100644 index 4c79e2863..000000000 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityConversion.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.mineinabyss.geary.minecraft.access - -import com.mineinabyss.geary.ecs.api.entities.GearyEntity -import org.bukkit.entity.Entity - -public fun Entity.toGeary(): GearyEntity = - BukkitAssociations.get(uniqueId) ?: BukkitEntityAssociations.registerEntity(this) - -// Separate function because inline `run` cannot be nullable -//TODO we want to call load entity event after init runs -public inline fun Entity.toGeary(init: GearyEntity.() -> Unit): GearyEntity = - toGeary().apply { init() } - -public fun Entity.toGearyOrNull(): GearyEntity? = BukkitAssociations[uniqueId] - -public fun GearyEntity.toBukkit(): Entity? = get() diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadManager.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadManager.kt deleted file mode 100644 index 14cdab0bd..000000000 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyLoadManager.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.mineinabyss.geary.minecraft.dsl - -import com.mineinabyss.geary.ecs.api.entities.GearyEntity -import com.mineinabyss.geary.ecs.serialization.Formats -import com.mineinabyss.geary.minecraft.GearyPlugin -import com.mineinabyss.geary.minecraft.events.GearyPrefabLoadEvent -import com.mineinabyss.idofront.events.call -import com.okkero.skedule.schedule -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject - -public object GearyLoadManager: KoinComponent { - private val plugin by inject() - internal val loadingPrefabs = mutableListOf() - private val actions = sortedMapOf Unit>>() - - public fun add(phase: GearyLoadPhase, action: () -> Unit) { - if (actions.isEmpty()) scheduleLoadTasks() - - actions.getOrPut(phase) { mutableListOf() }.add(action) - } - - private fun MutableList<() -> Unit>.runAll() = forEach { it() } - - private fun scheduleLoadTasks() { - plugin.schedule { - waitFor(1) - plugin.logger.info("Registering Serializers") - actions[GearyLoadPhase.REGISTER_SERIALIZERS]?.runAll() - Formats.createFormats() - plugin.logger.info("Loading prefabs") - actions[GearyLoadPhase.LOAD_PREFABS]?.runAll() - loadingPrefabs.forEach { - GearyPrefabLoadEvent(it).call() - } - loadingPrefabs.clear() - - waitFor(1) - plugin.logger.info("Running final startup tasks") - actions[GearyLoadPhase.ENABLE]?.runAll() - actions.clear() - } - } -} diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyEntityRemoveEvent.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyEntityRemoveEvent.kt deleted file mode 100644 index b308c6505..000000000 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyEntityRemoveEvent.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.mineinabyss.geary.minecraft.events - -import com.mineinabyss.geary.ecs.api.entities.GearyEntity -import org.bukkit.event.Event -import org.bukkit.event.HandlerList - - -/** - * Called whenever an entity with a related Bukkit Entity is asked to be removed from the ECS, - * before its components are actually cleared. - */ -//TODO maybe a more descriptive title and better documentation -//TODO Ensure calling Bukkit events during system iteration isn't going to cause any issues -public data class GearyEntityRemoveEvent( - val entity: GearyEntity -): Event() { - override fun getHandlers(): HandlerList = handlerList - - public companion object { - @JvmStatic - public val handlerList: HandlerList = HandlerList() - } -} diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyPrefabLoadEvent.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyPrefabLoadEvent.kt deleted file mode 100644 index e4fc5de81..000000000 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyPrefabLoadEvent.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.mineinabyss.geary.minecraft.events - -import com.mineinabyss.geary.ecs.api.entities.GearyEntity -import org.bukkit.event.Event -import org.bukkit.event.HandlerList - -public data class GearyPrefabLoadEvent( - val entity: GearyEntity -) : Event() { - override fun getHandlers(): HandlerList = handlerList - - internal companion object { - @JvmStatic - val handlerList = HandlerList() - } -} diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/listeners/GearyAttemptSpawnListener.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/listeners/GearyAttemptSpawnListener.kt deleted file mode 100644 index 5840c4a42..000000000 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/listeners/GearyAttemptSpawnListener.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.mineinabyss.geary.minecraft.listeners - -import com.mineinabyss.geary.minecraft.components.BukkitEntityType -import com.mineinabyss.geary.minecraft.events.GearyAttemptMinecraftSpawnEvent -import com.mineinabyss.idofront.spawning.spawn -import org.bukkit.event.EventHandler -import org.bukkit.event.Listener - -public object GearyAttemptSpawnListener: Listener { - @EventHandler - public fun GearyAttemptMinecraftSpawnEvent.readBukkitEntityType() { - if (bukkitEntity == null) - bukkitEntity = prefab.get()?.type?.let { location.spawn(it) } - } -} diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/listeners/InheritPrefabsOnLoad.kt b/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/listeners/InheritPrefabsOnLoad.kt deleted file mode 100644 index 14ea2bb4f..000000000 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/listeners/InheritPrefabsOnLoad.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.mineinabyss.geary.minecraft.listeners - -import com.mineinabyss.geary.minecraft.events.GearyPrefabLoadEvent -import com.mineinabyss.geary.prefabs.inheritPrefabs -import org.bukkit.event.EventHandler -import org.bukkit.event.Listener - -public class InheritPrefabsOnLoad : Listener { - @EventHandler - private fun GearyPrefabLoadEvent.onPrefabLoad() { - entity.inheritPrefabs() - } -} - diff --git a/platforms/papermc/build.gradle.kts b/platforms/papermc/build.gradle.kts new file mode 100644 index 000000000..05ad23a1c --- /dev/null +++ b/platforms/papermc/build.gradle.kts @@ -0,0 +1,35 @@ +plugins { + java + kotlin("plugin.serialization") + id("com.mineinabyss.conventions.copyjar") +} + +repositories { + mavenCentral() + maven("https://jitpack.io") +} + +configurations { + runtimeClasspath { + fun excludeDep(dep: Provider) { + val (group, module) = dep.get().module.toString().split(":") + exclude(group, module) + } + //TODO any libs here are included in our platform system on papermc, find a way to exclude all automatically + excludeDep(libs.koin.core) + excludeDep(libs.fastutil) + excludeDep(libs.kotlin.reflect) + excludeDep(libs.reflections) + } +} + +dependencies { + // Shaded + implementation(project(":geary-papermc-plugin")) +} + +tasks { + shadowJar { + archiveBaseName.set("Geary") + } +} diff --git a/platforms/geary-platform-papermc/build.gradle.kts b/platforms/papermc/core/build.gradle.kts similarity index 62% rename from platforms/geary-platform-papermc/build.gradle.kts rename to platforms/papermc/core/build.gradle.kts index 58914f625..0f0eadfaf 100644 --- a/platforms/geary-platform-papermc/build.gradle.kts +++ b/platforms/papermc/core/build.gradle.kts @@ -1,24 +1,23 @@ plugins { id("geary.kotlin-conventions") - id("com.mineinabyss.conventions.papermc") kotlin("plugin.serialization") + id("com.mineinabyss.conventions.publication") + id("com.mineinabyss.conventions.papermc") } repositories { - maven("https://jitpack.io") + mavenCentral() } dependencies { + api(project(":geary-addon")) + api(project(":geary-autoscan")) + api(project(":geary-core")) + api(project(":geary-prefabs")) + // MineInAbyss platform compileOnly(libs.kotlinx.coroutines) compileOnly(libs.minecraft.skedule) compileOnly(libs.kotlin.reflect) { isTransitive = false } - - // Shaded - api(project(":geary-core")) { - exclude(module = "kotlin-reflect") - } - api(project(":geary-prefabs")) - api(project(":geary-platform-papermc-core")) - implementation(gearylibs.reflections) + compileOnly(libs.reflections) } diff --git a/platforms/geary-platform-papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyConfig.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyConfig.kt similarity index 100% rename from platforms/geary-platform-papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyConfig.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyConfig.kt diff --git a/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyMCKoinComponent.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyMCKoinComponent.kt new file mode 100644 index 000000000..ceca17ba7 --- /dev/null +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyMCKoinComponent.kt @@ -0,0 +1,37 @@ +package com.mineinabyss.geary.papermc + +import com.mineinabyss.geary.api.addon.AbstractAddonManagerScope +import com.mineinabyss.geary.ecs.api.engine.EngineScope +import com.mineinabyss.geary.ecs.entities.UUID2GearyMap +import com.mineinabyss.geary.ecs.helpers.GearyKoinComponent +import com.mineinabyss.geary.papermc.access.BukkitEntity2Geary +import com.mineinabyss.geary.papermc.dsl.GearyAddonManager +import com.mineinabyss.geary.papermc.engine.PaperMCEngine +import com.mineinabyss.geary.prefabs.PrefabManager +import com.mineinabyss.geary.prefabs.PrefabManagerScope +import org.koin.core.component.inject + +public interface GearyScope : EngineScope, PrefabManagerScope, + AbstractAddonManagerScope, BukkitEntityAssociationsScope + +public interface BukkitEntityAssociationsScope { + public val bukkitEntity2Geary: BukkitEntity2Geary +} + +public open class GearyMCKoinComponent : GearyKoinComponent(), GearyScope { + override val engine: PaperMCEngine get() = super.engine as PaperMCEngine + override val prefabManager: PrefabManager by inject() + override val addonManager: GearyAddonManager by inject() + public override val bukkitEntity2Geary: BukkitEntity2Geary by inject() + + public val geary: GearyPlugin by inject() + public val bukkitAssociations: BukkitEntity2Geary by inject() + + public val uuid2entity: UUID2GearyMap by inject() + + public companion object { + public inline operator fun invoke(run: GearyMCKoinComponent.() -> T): T { + return GearyMCKoinComponent().run(run) + } + } +} diff --git a/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyPlugin.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyPlugin.kt new file mode 100644 index 000000000..bbacbd6be --- /dev/null +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/GearyPlugin.kt @@ -0,0 +1,5 @@ +package com.mineinabyss.geary.papermc + +import org.bukkit.plugin.java.JavaPlugin + +public abstract class GearyPlugin: JavaPlugin() diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/Helpers.kt similarity index 62% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/Helpers.kt index 804cee478..5ee967732 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/Helpers.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/Helpers.kt @@ -1,14 +1,10 @@ -package com.mineinabyss.geary.minecraft +package com.mineinabyss.geary.papermc -import com.mineinabyss.geary.ecs.api.engine.globalEngine import com.mineinabyss.geary.ecs.api.entities.GearyEntity -import com.mineinabyss.geary.minecraft.access.toGeary -import com.mineinabyss.geary.minecraft.engine.SpigotEngine -import com.mineinabyss.geary.minecraft.events.GearyAttemptMinecraftSpawnEvent -import com.mineinabyss.geary.minecraft.events.GearyMinecraftSpawnEvent -import com.mineinabyss.geary.papermc.GearyConfig +import com.mineinabyss.geary.papermc.access.toGeary +import com.mineinabyss.geary.papermc.events.GearyAttemptMinecraftSpawnEvent +import com.mineinabyss.geary.papermc.events.GearyMinecraftSpawnEvent import com.mineinabyss.geary.prefabs.PrefabKey -import com.mineinabyss.geary.prefabs.PrefabManager import com.mineinabyss.geary.prefabs.helpers.addPrefab import com.mineinabyss.idofront.events.call import com.mineinabyss.idofront.messaging.broadcast @@ -26,17 +22,17 @@ internal fun KoinComponent.debug(message: Any?) { /** Verifies a [PersistentDataContainer] has a tag identifying it as containing Geary components. */ public var PersistentDataContainer.hasComponentsEncoded: Boolean - get() = has((globalEngine as SpigotEngine).componentsKey, PersistentDataType.BYTE) - set(value) { + get() = GearyMCKoinComponent { has(engine.componentsKey, PersistentDataType.BYTE) } + set(value) = GearyMCKoinComponent { when { //TODO are there any empty marker keys? - value -> if (!hasComponentsEncoded) set((globalEngine as SpigotEngine).componentsKey, PersistentDataType.BYTE, 1) - else -> remove((globalEngine as SpigotEngine).componentsKey) + value -> if (!hasComponentsEncoded) set(engine.componentsKey, PersistentDataType.BYTE, 1) + else -> remove(engine.componentsKey) } } -public fun Location.spawnFromPrefab(prefab: PrefabKey): Entity? { - return spawnFromPrefab(PrefabManager[prefab] ?: return null) +public fun Location.spawnFromPrefab(prefab: PrefabKey): Entity? = GearyMCKoinComponent { + return spawnFromPrefab(prefabManager[prefab] ?: return null) } public fun Location.spawnFromPrefab(prefab: GearyEntity): Entity? { diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/StartupEventListener.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/StartupEventListener.kt similarity index 94% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/StartupEventListener.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/StartupEventListener.kt index 26b07ed2b..f4480a60b 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/StartupEventListener.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/StartupEventListener.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft +package com.mineinabyss.geary.papermc import org.bukkit.Bukkit import org.bukkit.event.EventHandler diff --git a/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntity2Geary.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntity2Geary.kt new file mode 100644 index 000000000..ebb93fc99 --- /dev/null +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntity2Geary.kt @@ -0,0 +1,118 @@ +package com.mineinabyss.geary.papermc.access + +import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent +import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent +import com.destroystokyo.paper.event.player.PlayerPostRespawnEvent +import com.mineinabyss.geary.ecs.accessors.TargetScope +import com.mineinabyss.geary.ecs.accessors.building.get +import com.mineinabyss.geary.ecs.api.annotations.Handler +import com.mineinabyss.geary.ecs.api.engine.systems +import com.mineinabyss.geary.ecs.api.entities.GearyEntity +import com.mineinabyss.geary.ecs.api.entities.toGeary +import com.mineinabyss.geary.ecs.api.systems.GearyListener +import com.mineinabyss.geary.ecs.events.EntityRemoved +import com.mineinabyss.geary.papermc.GearyMCKoinComponent +import com.mineinabyss.geary.papermc.hasComponentsEncoded +import com.mineinabyss.geary.papermc.store.decodeComponentsFrom +import com.mineinabyss.geary.papermc.store.encodeComponentsTo +import com.mineinabyss.idofront.plugin.registerEvents +import com.mineinabyss.idofront.typealiases.BukkitEntity +import it.unimi.dsi.fastutil.ints.Int2LongOpenHashMap +import org.bukkit.entity.Player +import org.bukkit.event.EventHandler +import org.bukkit.event.EventPriority +import org.bukkit.event.Listener +import org.bukkit.event.player.PlayerJoinEvent +import org.bukkit.event.player.PlayerQuitEvent +import kotlin.collections.set + +public class BukkitEntity2Geary : Listener, GearyMCKoinComponent() { + private val entityMap = Int2LongOpenHashMap().apply { defaultReturnValue(-1) } + + public fun startTracking() { + geary.registerEvents(this) + systems(Register(), Unregister()) + } + + public operator fun get(entityId: Int): GearyEntity? { + val id = entityMap.get(entityId) + if (id == -1L) return null + return id.toGeary() + } + + public operator fun set(bukkit: BukkitEntity, entity: GearyEntity) { + entityMap[bukkit.entityId] = entity.id.toLong() + } + + public operator fun contains(entityId: Int): Boolean = entityMap.containsKey(entityId) + + public fun remove(entityId: Int): GearyEntity? { + return entityMap.remove(entityId).takeIf { it != -1L }?.toGeary() + } + + private inner class Register : GearyListener() { + val TargetScope.bukkit by added() + + @Handler + fun TargetScope.loadPersisted() { + set(bukkit, entity) + + val pdc = bukkit.persistentDataContainer + if (pdc.hasComponentsEncoded) + entity.decodeComponentsFrom(pdc) + // allow us to both get the BukkitEntity and specific class (ex Player) + bukkit.type.entityClass?.kotlin?.let { bukkitClass -> + entity.set(bukkit, bukkitClass) + } + + entity.set(bukkit.uniqueId) + } + } + + private inner class Unregister : GearyListener() { + val TargetScope.bukkit by get() + + init { + event.has() + } + + @Handler + fun TargetScope.persistComponents() { + remove(bukkit.entityId) + entity.encodeComponentsTo(bukkit) + } + } + + /** Remove entities from ECS when they are removed from Bukkit for any reason (Uses PaperMC event) */ + @EventHandler(priority = EventPriority.LOWEST) + public fun EntityAddToWorldEvent.onBukkitEntityAdd() { + // Only remove player from ECS on disconnect, not death + if (entity is Player) return + entity.toGeary() + } + + @EventHandler(priority = EventPriority.LOWEST) + public fun PlayerJoinEvent.onPlayerLogin() { + player.toGeary() + } + + /** Remove entities from ECS when they are removed from Bukkit for any reason (Uses PaperMC event) */ + @EventHandler(priority = EventPriority.HIGHEST) + public fun EntityRemoveFromWorldEvent.onBukkitEntityRemove() { + // Only remove player from ECS on disconnect, not death + if (entity is Player) return + entity.toGearyOrNull()?.removeEntity() + } + + @EventHandler(priority = EventPriority.LOWEST) + public fun PlayerQuitEvent.onPlayerLogout() { + player.toGearyOrNull()?.removeEntity() + } + + /** Player death counts as an entity being removed from the world so we should add them back after respawn */ + @EventHandler(priority = EventPriority.LOWEST) + public fun PlayerPostRespawnEvent.onPlayerRespawn() { + //TODO add Dead component on death and remove it here + // Or should we add an inactive component that prevents systems from iterating over dead players? + } +} diff --git a/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntityConversion.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntityConversion.kt new file mode 100644 index 000000000..e3c783dea --- /dev/null +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntityConversion.kt @@ -0,0 +1,22 @@ +package com.mineinabyss.geary.papermc.access + +import com.mineinabyss.geary.ecs.api.engine.entity +import com.mineinabyss.geary.ecs.api.entities.GearyEntity +import com.mineinabyss.geary.papermc.GearyMCKoinComponent +import com.mineinabyss.idofront.typealiases.BukkitEntity +import org.bukkit.entity.Entity + +public fun BukkitEntity.toGeary(): GearyEntity = GearyMCKoinComponent { + bukkitAssociations[entityId] ?: entity { set(this@toGeary) } +} + +// Separate function because inline `run` cannot be nullable +//TODO we want to call load entity event after init runs +public inline fun BukkitEntity.toGeary(init: GearyEntity.() -> Unit): GearyEntity = + toGeary().apply { init() } + +public fun BukkitEntity.toGearyOrNull(): GearyEntity? = GearyMCKoinComponent().run { + bukkitAssociations[entityId] +} + +public fun GearyEntity.toBukkit(): BukkitEntity? = get() diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityConversionGenerics.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntityConversionGenerics.kt similarity index 85% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityConversionGenerics.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntityConversionGenerics.kt index 76608253d..dcb1874f3 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/access/BukkitEntityConversionGenerics.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/access/BukkitEntityConversionGenerics.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.access +package com.mineinabyss.geary.papermc.access import com.mineinabyss.geary.ecs.api.entities.GearyEntity import org.bukkit.entity.Entity diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/components/BukkitEntityType.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/components/BukkitEntityType.kt similarity index 82% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/components/BukkitEntityType.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/components/BukkitEntityType.kt index 73c057b2e..0dd828fdf 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/components/BukkitEntityType.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/components/BukkitEntityType.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.components +package com.mineinabyss.geary.papermc.components import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/components/PrefabKeyHelpers.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/components/PrefabKeyHelpers.kt similarity index 87% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/components/PrefabKeyHelpers.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/components/PrefabKeyHelpers.kt index 8b358a93c..b4254ab70 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/components/PrefabKeyHelpers.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/components/PrefabKeyHelpers.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.components +package com.mineinabyss.geary.papermc.components import com.mineinabyss.geary.prefabs.PrefabKey import com.mineinabyss.geary.prefabs.PrefabManager diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/AutoScanner.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/dsl/AutoScanner.kt similarity index 96% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/AutoScanner.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/dsl/AutoScanner.kt index c8424da59..8ab7bae3e 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/AutoScanner.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/dsl/AutoScanner.kt @@ -1,6 +1,6 @@ -package com.mineinabyss.geary.minecraft.dsl +package com.mineinabyss.geary.papermc.dsl -import com.mineinabyss.geary.ecs.api.autoscan.ExcludeAutoScan +import com.mineinabyss.geary.autoscan.ExcludeAutoScan import com.mineinabyss.idofront.messaging.logWarn import kotlinx.serialization.modules.SerializersModule import org.reflections.Reflections diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyAddon.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/dsl/GearyAddon.kt similarity index 51% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyAddon.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/dsl/GearyAddon.kt index 1c55b257e..5b9aebc57 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/dsl/GearyAddon.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/dsl/GearyAddon.kt @@ -1,26 +1,24 @@ -package com.mineinabyss.geary.minecraft.dsl +package com.mineinabyss.geary.papermc.dsl +import com.mineinabyss.geary.api.addon.AbstractGearyAddon +import com.mineinabyss.geary.api.addon.GearyLoadPhase +import com.mineinabyss.geary.autoscan.AutoScan +import com.mineinabyss.geary.autoscan.ExcludeAutoScan import com.mineinabyss.geary.ecs.api.GearyComponent -import com.mineinabyss.geary.ecs.api.autoscan.AutoScan -import com.mineinabyss.geary.ecs.api.autoscan.ExcludeAutoScan -import com.mineinabyss.geary.ecs.api.engine.globalEngine import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.systems.GearySystem import com.mineinabyss.geary.ecs.serialization.Formats -import com.mineinabyss.geary.minecraft.access.BukkitEntityAssociations +import com.mineinabyss.geary.papermc.GearyMCKoinComponent +import com.mineinabyss.geary.papermc.GearyScope import com.mineinabyss.geary.prefabs.PrefabKey -import com.mineinabyss.geary.prefabs.PrefabManager import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.modules.PolymorphicModuleBuilder -import kotlinx.serialization.modules.SerializersModule -import kotlinx.serialization.modules.SerializersModuleBuilder import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.serializerOrNull import org.bukkit.entity.Entity import org.bukkit.plugin.Plugin -import java.io.File import kotlin.reflect.KClass import kotlin.reflect.full.createInstance import kotlin.reflect.full.hasAnnotation @@ -36,8 +34,10 @@ internal annotation class GearyAddonDSL */ @GearyAddonDSL public class GearyAddon( - public val plugin: Plugin -) { + public val plugin: Plugin, +) : AbstractGearyAddon(), GearyScope by GearyMCKoinComponent() { + override val namespace: String = plugin.name.lowercase() + public val classLoader: ClassLoader = plugin::class.java.classLoader /** @@ -130,112 +130,6 @@ public class GearyAddon( } } } - - /** Adds a [SerializersModule] for polymorphic serialization of [GearyComponent]s within the ECS. */ - public inline fun components(crossinline init: PolymorphicModuleBuilder.() -> Unit) { - serializers { polymorphic(GearyComponent::class) { init() } } - } - - /** Registers a [system]. */ - public fun system(system: GearySystem) { - globalEngine.addSystem(system) - } - - /** Registers a list of [systems]. */ - public fun systems(vararg systems: GearySystem) { - systems.forEach { system(it) } - } - - /** - * Adds a serializable component and registers it with Geary to allow finding the appropriate class via - * component serial name. - */ - public inline fun PolymorphicModuleBuilder.component(serializer: KSerializer) { - component(T::class, serializer) - } - - /** - * Adds a serializable component and registers it with Geary to allow finding the appropriate class via - * component serial name. - */ - public fun PolymorphicModuleBuilder.component( - kClass: KClass, - serializer: KSerializer? - ): Boolean { - val serialName = serializer?.descriptor?.serialName ?: return false - if (!Formats.isRegistered(serialName)) { - Formats.registerSerialName(serialName, kClass) - subclass(kClass, serializer) - return true - } - return false - } - - /** Adds a [SerializersModule] to be used for polymorphic serialization within the ECS. */ - public inline fun serializers(init: SerializersModuleBuilder.() -> Unit) { - Formats.addSerializerModule(plugin.name, SerializersModule { init() }) - } - - /** Entry point for extending behaviour regarding how bukkit entities are linked to the ECS. */ - public inline fun bukkitEntityAssociations(init: BukkitEntityAssociationsAddon.() -> Unit) { - BukkitEntityAssociationsAddon().apply(init) - } - - /** Entry point for extending behaviour regarding how bukkit entities are linked to the ECS. */ - public class BukkitEntityAssociationsAddon { - /** Additional things to do or components to be added to an [Entity] of type [T] is registered with the ECS. */ - public inline fun onEntityRegister(crossinline run: GearyEntity.(T) -> Unit) { - BukkitEntityAssociations.onBukkitEntityRegister { entity -> - if (entity is T) run(entity) - } - } - - /** Additional things to do before an [Entity] of type [T] is removed from the ECS (or Minecraft World). */ - public inline fun onEntityUnregister(crossinline run: GearyEntity.(T) -> Unit) { - BukkitEntityAssociations.onBukkitEntityUnregister { entity -> - if (entity is T) run(entity) - } - } - } - - /** Loads prefab entities from all files inside a [directory][from], into a given [namespace] */ - public fun loadPrefabs( - from: File, - namespace: String = plugin.name.lowercase() - ) { - startup { - GearyLoadPhase.LOAD_PREFABS { - // Start with the innermost directories - val dirs = from.walkBottomUp().filter { it.isDirectory } - val files = dirs.flatMap { dir -> dir.walk().maxDepth(1).filter { it.isFile } } - files.forEach { file -> - val entity = PrefabManager.loadFromFile(namespace, file) ?: return@forEach - GearyLoadManager.loadingPrefabs += entity - } - } - } - } - - public class PhaseCreator { - public operator fun GearyLoadPhase.invoke(run: () -> Unit) { - GearyLoadManager.add(this, run) - } - } - - /** - * Allows defining actions that should run at a specific phase during startup - * - * Within its context, invoke a [GearyLoadPhase] to run something during it, ex: - * - * ``` - * GearyLoadPhase.ENABLE { - * // run code here - * } - * ``` - */ - public inline fun startup(run: PhaseCreator.() -> Unit) { - PhaseCreator().apply(run) - } } /** The polymorphic builder scope that allows registering subclasses. */ diff --git a/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/dsl/GearyAddonManager.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/dsl/GearyAddonManager.kt new file mode 100644 index 000000000..0af702453 --- /dev/null +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/dsl/GearyAddonManager.kt @@ -0,0 +1,20 @@ +package com.mineinabyss.geary.papermc.dsl + +import com.mineinabyss.geary.api.addon.AbstractAddonManager +import com.mineinabyss.geary.papermc.GearyPlugin +import com.okkero.skedule.schedule +import org.koin.core.component.inject + +public class GearyAddonManager() : AbstractAddonManager() { + private val plugin by inject() + + override fun scheduleLoadTasks() { + plugin.schedule { + // After one server tick, all plugins are guaranteed to have loaded + waitFor(1) + load() + waitFor(1) + enableAddons() + } + } +} diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/engine/PaperMCEngine.kt similarity index 71% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/engine/PaperMCEngine.kt index 02c4ae046..652f7b75e 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/engine/SpigotEngine.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/engine/PaperMCEngine.kt @@ -1,12 +1,9 @@ -package com.mineinabyss.geary.minecraft.engine +package com.mineinabyss.geary.papermc.engine import co.aikar.timings.Timings -import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.systems.GearySystem import com.mineinabyss.geary.ecs.api.systems.TickingSystem import com.mineinabyss.geary.ecs.engine.GearyEngine -import com.mineinabyss.geary.minecraft.events.GearyEntityRemoveEvent -import com.mineinabyss.idofront.events.call import com.mineinabyss.idofront.plugin.registerEvents import com.okkero.skedule.schedule import org.bukkit.Bukkit @@ -14,9 +11,8 @@ import org.bukkit.NamespacedKey import org.bukkit.event.Listener import org.bukkit.plugin.Plugin import org.koin.core.component.KoinComponent -import java.util.* -public class SpigotEngine(private val plugin: Plugin) : GearyEngine(), KoinComponent { +public class PaperMCEngine(private val plugin: Plugin) : GearyEngine(), KoinComponent { public val componentsKey: NamespacedKey = NamespacedKey(plugin, "components") override fun TickingSystem.runSystem() { @@ -47,11 +43,4 @@ public class SpigotEngine(private val plugin: Plugin) : GearyEngine(), KoinCompo } } } - - override fun removeEntity(entity: GearyEntity) { - if (entity.has()) - //TODO this should be unnecessary now - GearyEntityRemoveEvent(entity).call() - super.removeEntity(entity) - } } diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyAttemptMinecraftSpawnEvent.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/events/GearyAttemptMinecraftSpawnEvent.kt similarity index 91% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyAttemptMinecraftSpawnEvent.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/events/GearyAttemptMinecraftSpawnEvent.kt index f2cea161f..22b3161bf 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyAttemptMinecraftSpawnEvent.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/events/GearyAttemptMinecraftSpawnEvent.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.events +package com.mineinabyss.geary.papermc.events import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.idofront.typealiases.BukkitEntity diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyMinecraftSpawnEvent.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/events/GearyMinecraftSpawnEvent.kt similarity index 92% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyMinecraftSpawnEvent.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/events/GearyMinecraftSpawnEvent.kt index 804233156..5939f9f54 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/events/GearyMinecraftSpawnEvent.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/events/GearyMinecraftSpawnEvent.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.events +package com.mineinabyss.geary.papermc.events import com.mineinabyss.geary.ecs.api.entities.GearyEntity import org.bukkit.event.Event diff --git a/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/events/GearyPrefabLoadEvent.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/events/GearyPrefabLoadEvent.kt new file mode 100644 index 000000000..4dcee5964 --- /dev/null +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/events/GearyPrefabLoadEvent.kt @@ -0,0 +1,2 @@ +package com.mineinabyss.geary.papermc.events + diff --git a/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/listeners/GearyAttemptSpawnListener.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/listeners/GearyAttemptSpawnListener.kt new file mode 100644 index 000000000..591d6bcd8 --- /dev/null +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/listeners/GearyAttemptSpawnListener.kt @@ -0,0 +1,17 @@ +package com.mineinabyss.geary.papermc.listeners + +import com.mineinabyss.geary.ecs.api.systems.GearyListener +import com.mineinabyss.geary.papermc.components.BukkitEntityType +import com.mineinabyss.geary.papermc.events.GearyAttemptMinecraftSpawnEvent +import com.mineinabyss.idofront.spawning.spawn +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener + +public object GearyAttemptSpawnListener : Listener, GearyListener() { + // val TargetScope.entityType + @EventHandler + public fun GearyAttemptMinecraftSpawnEvent.readBukkitEntityType() { + if (bukkitEntity == null) + bukkitEntity = prefab.get()?.type?.let { location.spawn(it) } + } +} diff --git a/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/listeners/InheritPrefabsOnLoad.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/listeners/InheritPrefabsOnLoad.kt new file mode 100644 index 000000000..d94e564b8 --- /dev/null +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/listeners/InheritPrefabsOnLoad.kt @@ -0,0 +1,21 @@ +package com.mineinabyss.geary.papermc.listeners + +import com.mineinabyss.geary.autoscan.AutoScan +import com.mineinabyss.geary.ecs.accessors.TargetScope +import com.mineinabyss.geary.ecs.api.annotations.Handler +import com.mineinabyss.geary.ecs.api.systems.GearyListener +import com.mineinabyss.geary.prefabs.events.PrefabLoaded +import com.mineinabyss.geary.prefabs.helpers.inheritPrefabs + +@AutoScan +public class InheritPrefabsOnLoad : GearyListener() { + init { + event.has() + } + + @Handler + private fun TargetScope.inheritOnLoad() { + entity.inheritPrefabs() + } +} + diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/ContainerHelpers.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/ContainerHelpers.kt similarity index 97% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/ContainerHelpers.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/ContainerHelpers.kt index 4b927e50d..1f81a1409 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/ContainerHelpers.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/ContainerHelpers.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.store +package com.mineinabyss.geary.papermc.store import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.api.entities.toGeary diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/DataStore.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/DataStore.kt similarity index 85% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/DataStore.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/DataStore.kt index bed07a687..3bed40f44 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/DataStore.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/DataStore.kt @@ -1,14 +1,13 @@ -package com.mineinabyss.geary.minecraft.store +package com.mineinabyss.geary.papermc.store import com.mineinabyss.geary.ecs.api.GearyComponent import com.mineinabyss.geary.ecs.api.GearyType -import com.mineinabyss.geary.ecs.api.engine.globalEngine import com.mineinabyss.geary.ecs.api.entities.toGeary import com.mineinabyss.geary.ecs.engine.isInstance import com.mineinabyss.geary.ecs.serialization.Formats import com.mineinabyss.geary.ecs.serialization.Formats.cborFormat -import com.mineinabyss.geary.minecraft.engine.SpigotEngine -import com.mineinabyss.geary.minecraft.hasComponentsEncoded +import com.mineinabyss.geary.papermc.GearyMCKoinComponent +import com.mineinabyss.geary.papermc.hasComponentsEncoded import com.mineinabyss.geary.prefabs.PrefabKey import com.mineinabyss.idofront.util.toMCKey import kotlinx.serialization.DeserializationStrategy @@ -69,18 +68,20 @@ public inline fun PersistentDataContainer.decode( * * @see encode */ -public fun PersistentDataContainer.encodeComponents(components: Collection, type: GearyType) { - hasComponentsEncoded = true - //remove all keys present on the PDC so we only end up with the new list of components being encoded - keys.filter { it.namespace == "geary" && it != (globalEngine as SpigotEngine).componentsKey }.forEach { remove(it) } +public fun PersistentDataContainer.encodeComponents(components: Collection, type: GearyType): Unit = + GearyMCKoinComponent { + hasComponentsEncoded = true + //remove all keys present on the PDC so we only end up with the new list of components being encoded + keys.filter { it.namespace == "geary" && it != engine.componentsKey } + .forEach { remove(it) } - for (value in components) - encode(value) + for (value in components) + encode(value) - val prefabs = type.filter { it.isInstance() } - if (!prefabs.inner.isEmpty()) - encodePrefabs(prefabs.inner.mapNotNull { it.toGeary().get() }) -} + val prefabs = type.filter { it.isInstance() } + if (!prefabs.inner.isEmpty()) + encodePrefabs(prefabs.inner.mapNotNull { it.toGeary().get() }) + } /** * Encodes a list of [PrefabKey]s under the key `geary:prefabs`. When decoding these will be stored in diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/DecodedEntityData.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/DecodedEntityData.kt similarity index 83% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/DecodedEntityData.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/DecodedEntityData.kt index 9b9f42449..f3d7b5ab2 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/DecodedEntityData.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/DecodedEntityData.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.store +package com.mineinabyss.geary.papermc.store import com.mineinabyss.geary.ecs.api.GearyComponent import com.mineinabyss.geary.ecs.api.GearyType diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/FileSystemStore.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/FileSystemStore.kt similarity index 97% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/FileSystemStore.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/FileSystemStore.kt index 2b945f748..1f371dbca 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/FileSystemStore.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/FileSystemStore.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.store +package com.mineinabyss.geary.papermc.store import com.mineinabyss.geary.ecs.api.entities.GearyEntity import com.mineinabyss.geary.ecs.serialization.Formats diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/FormatExtensions.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/FormatExtensions.kt similarity index 94% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/FormatExtensions.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/FormatExtensions.kt index 1ee9e9833..c5c7261b8 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/FormatExtensions.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/FormatExtensions.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.store +package com.mineinabyss.geary.papermc.store import com.mineinabyss.geary.ecs.api.GearyComponent import com.mineinabyss.geary.ecs.serialization.Formats diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/GearyStore.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/GearyStore.kt similarity index 95% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/GearyStore.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/GearyStore.kt index 209a6f797..02ef17c8f 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/GearyStore.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/GearyStore.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.store +package com.mineinabyss.geary.papermc.store import com.mineinabyss.geary.ecs.api.GearyComponent import com.mineinabyss.geary.ecs.api.entities.GearyEntity diff --git a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/NamespacedKeyHelpers.kt b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/NamespacedKeyHelpers.kt similarity index 97% rename from platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/NamespacedKeyHelpers.kt rename to platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/NamespacedKeyHelpers.kt index dd3fc3f0c..a60de4f1f 100644 --- a/platforms/geary-platform-papermc/src/main/kotlin/com/mineinabyss/geary/minecraft/store/NamespacedKeyHelpers.kt +++ b/platforms/papermc/core/src/main/kotlin/com/mineinabyss/geary/papermc/store/NamespacedKeyHelpers.kt @@ -1,4 +1,4 @@ -package com.mineinabyss.geary.minecraft.store +package com.mineinabyss.geary.papermc.store import com.mineinabyss.idofront.util.toMCKey import org.bukkit.NamespacedKey diff --git a/platforms/papermc/plugin/build.gradle.kts b/platforms/papermc/plugin/build.gradle.kts new file mode 100644 index 000000000..99ec26509 --- /dev/null +++ b/platforms/papermc/plugin/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + id("geary.kotlin-conventions") + id("com.mineinabyss.conventions.papermc") + kotlin("plugin.serialization") +} + +repositories { + maven("https://raw.githubusercontent.com/TheBlackEntity/PlugMan/repository/") +} + +dependencies { + // Shaded + api(project(":geary-papermc-core")) + api(project(":geary-web-console")) + + // Other plugins + compileOnly(gearylibs.plugman) +} diff --git a/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt b/platforms/papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt similarity index 84% rename from platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt rename to platforms/papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt index a51ade49d..a8d88bdae 100644 --- a/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt +++ b/platforms/papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyCommands.kt @@ -3,26 +3,33 @@ package com.mineinabyss.geary.papermc.plugin import com.mineinabyss.geary.ecs.api.GearyType import com.mineinabyss.geary.ecs.engine.countChildren import com.mineinabyss.geary.ecs.engine.getArchetype -import com.mineinabyss.geary.minecraft.StartupEventListener +import com.mineinabyss.geary.papermc.StartupEventListener import com.mineinabyss.geary.prefabs.PrefabKey import com.mineinabyss.geary.prefabs.PrefabManager import com.mineinabyss.idofront.commands.arguments.stringArg import com.mineinabyss.idofront.commands.execution.IdofrontCommandExecutor import com.mineinabyss.idofront.commands.execution.stopCommand import com.mineinabyss.idofront.messaging.info +import com.mineinabyss.idofront.spawning.spawn import com.rylinaux.plugman.util.PluginUtil +import org.bukkit.Location +import org.bukkit.block.BlockFace import org.bukkit.command.CommandSender import org.bukkit.command.TabCompleter -import org.bukkit.plugin.Plugin +import org.bukkit.entity.ArmorStand import org.bukkit.plugin.java.JavaPlugin +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject + +internal class GearyCommands(val plugin: JavaPlugin) : IdofrontCommandExecutor(), TabCompleter, KoinComponent { + val prefabManager: PrefabManager by inject() -internal class GearyCommands(val plugin: JavaPlugin) : IdofrontCommandExecutor(), TabCompleter { override val commands = commands(plugin) { "geary" { "reread" { val prefab by stringArg() action { - PrefabManager.reread( + prefabManager.reread( PrefabKey.ofOrNull(prefab)?.toEntity() ?: command.stopCommand("Prefab key not found") ) } @@ -67,7 +74,7 @@ internal class GearyCommands(val plugin: JavaPlugin) : IdofrontCommandExecutor() ) 2 -> { when (args[0]) { - "reread" -> PrefabManager.keys.filter { + "reread" -> prefabManager.keys.filter { val arg = args[1].lowercase() it.name.startsWith(arg) || it.key.startsWith(arg) }.map { it.toString() } diff --git a/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt b/platforms/papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt similarity index 67% rename from platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt rename to platforms/papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt index d6cf193c1..c222c84b2 100644 --- a/platforms/geary-platform-papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt +++ b/platforms/papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt @@ -1,24 +1,24 @@ package com.mineinabyss.geary.papermc.plugin +import com.mineinabyss.geary.api.addon.GearyLoadPhase.ENABLE import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.systems.QueryManager -import com.mineinabyss.geary.ecs.engine.GearyEngine +import com.mineinabyss.geary.ecs.entities.UUID2GearyMap +import com.mineinabyss.geary.ecs.helpers.GearyKoinComponent import com.mineinabyss.geary.ecs.serialization.Formats import com.mineinabyss.geary.ecs.serialization.withSerialName -import com.mineinabyss.geary.ecs.helpers.GearyKoinComponent -import com.mineinabyss.geary.minecraft.GearyPlugin -import com.mineinabyss.geary.minecraft.StartupEventListener -import com.mineinabyss.geary.minecraft.access.BukkitAssociations -import com.mineinabyss.geary.minecraft.access.BukkitEntityAssociations -import com.mineinabyss.geary.minecraft.access.toGeary -import com.mineinabyss.geary.minecraft.dsl.GearyLoadPhase -import com.mineinabyss.geary.minecraft.dsl.gearyAddon -import com.mineinabyss.geary.minecraft.engine.SpigotEngine -import com.mineinabyss.geary.minecraft.listeners.GearyAttemptSpawnListener -import com.mineinabyss.geary.minecraft.listeners.InheritPrefabsOnLoad -import com.mineinabyss.geary.minecraft.store.FileSystemStore -import com.mineinabyss.geary.minecraft.store.GearyStore import com.mineinabyss.geary.papermc.GearyConfig +import com.mineinabyss.geary.papermc.GearyPlugin +import com.mineinabyss.geary.papermc.StartupEventListener +import com.mineinabyss.geary.papermc.access.BukkitEntity2Geary +import com.mineinabyss.geary.papermc.access.toGeary +import com.mineinabyss.geary.papermc.dsl.GearyAddonManager +import com.mineinabyss.geary.papermc.dsl.gearyAddon +import com.mineinabyss.geary.papermc.engine.PaperMCEngine +import com.mineinabyss.geary.papermc.listeners.GearyAttemptSpawnListener +import com.mineinabyss.geary.papermc.store.FileSystemStore +import com.mineinabyss.geary.papermc.store.GearyStore +import com.mineinabyss.geary.prefabs.PrefabManager import com.mineinabyss.geary.webconsole.GearyWebConsole import com.mineinabyss.geary.webconsole.webConsole import com.mineinabyss.idofront.config.singleConfig @@ -28,7 +28,6 @@ import com.mineinabyss.idofront.plugin.registerEvents import com.mineinabyss.idofront.plugin.registerService import com.mineinabyss.idofront.serialization.UUIDSerializer import org.bukkit.Bukkit -import org.koin.core.component.get import org.koin.dsl.module import java.util.* import kotlin.io.path.div @@ -46,26 +45,35 @@ public class GearyPluginImpl : GearyPlugin() { saveDefaultConfig() reloadConfig() val webConsole = GearyWebConsole() - val engine = SpigotEngine(this@GearyPluginImpl) + val engine = PaperMCEngine(this@GearyPluginImpl) val queryManager = QueryManager(engine) + val bukkitEntity2Geary = BukkitEntity2Geary() + val uuid2GearyMap = UUID2GearyMap() + val addonManager = GearyAddonManager() + val prefabManager = PrefabManager(engine) + startOrAppendKoin(module { single { this@GearyPluginImpl } single { webConsole } single { queryManager } single { engine } + single { bukkitEntity2Geary } + single { uuid2GearyMap } + single { addonManager } + single { prefabManager } singleConfig(GearyConfig.serializer(), this@GearyPluginImpl) }) + engine.start() webConsole.start() + uuid2GearyMap.startTracking() + bukkitEntity2Geary.startTracking() // Register commands. GearyCommands(this) registerEvents( - BukkitEntityAssociations, - BukkitAssociations, GearyAttemptSpawnListener, - InheritPrefabsOnLoad(), ) // This will also register a serializer for GearyEntityType @@ -83,7 +91,7 @@ public class GearyPluginImpl : GearyPlugin() { ?.forEach { loadPrefabs(it, namespace = it.name) } startup { - GearyLoadPhase.ENABLE { + ENABLE { registerService(FileSystemStore(dataFolder.toPath() / "serialized")) Bukkit.getOnlinePlayers().forEach { it.toGeary() } } diff --git a/platforms/geary-platform-papermc/plugin/src/main/resources/config.yml b/platforms/papermc/plugin/src/main/resources/config.yml similarity index 100% rename from platforms/geary-platform-papermc/plugin/src/main/resources/config.yml rename to platforms/papermc/plugin/src/main/resources/config.yml diff --git a/platforms/geary-platform-papermc/plugin/src/main/resources/plugin.yml b/platforms/papermc/plugin/src/main/resources/plugin.yml similarity index 100% rename from platforms/geary-platform-papermc/plugin/src/main/resources/plugin.yml rename to platforms/papermc/plugin/src/main/resources/plugin.yml diff --git a/settings.gradle.kts b/settings.gradle.kts index 3d33b85fb..90bc0f67a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -42,24 +42,30 @@ dependencyResolutionManagement { alias("bimap").to("com.uchuhimo", "kotlinx-bimap").versionRef("bimap-test") alias("bitvector").to("net.onedaybeard.bitvector:bitvector-jvm:0.1.4") alias("fastutil").to("it.unimi.dsi:fastutil:8.2.2") //Version on minecraft server - alias("reflections").to("org.reflections:reflections:0.9.12") alias("plugman").to("com.rylinaux:PlugMan:2.2.5") } } } include( + "geary-autoscan", + "geary-addon", "geary-core", "geary-prefabs", "geary-web-console", - "geary-platform-papermc", - "geary-platform-papermc-core", - "geary-platform-papermc-plugin", + "geary-papermc", ) -project(":geary-platform-papermc").projectDir = file("./platforms/geary-platform-papermc") -project(":geary-platform-papermc-core").projectDir = file("./platforms/geary-platform-papermc/core") -project(":geary-platform-papermc-plugin").projectDir = file("./platforms/geary-platform-papermc/plugin") +project(":geary-papermc").projectDir = file("./platforms/papermc") + +file("./platforms/papermc") + .listFiles()!! + .filter { it.isDirectory && it.name !in setOf("src", "build") } + .forEach { + val name = "geary-papermc-${it.name}" + include(name) + project(":$name").projectDir = it + } includeBuild("geary-conventions") includeBuild("../Idofront") From eb4f15e0cd5dcad5302a7fc5d2553d7f8d31cd94 Mon Sep 17 00:00:00 2001 From: 0ffz Date: Thu, 27 Jan 2022 19:25:21 -0500 Subject: [PATCH 5/6] Synchronize archetype component operations, don't put web console in papermc --- .../geary/ecs/api/entities/GearyEntity.kt | 3 +- .../mineinabyss/geary/ecs/engine/Archetype.kt | 100 +++++++++--------- platforms/papermc/plugin/build.gradle.kts | 1 - .../geary/papermc/plugin/GearyPluginImpl.kt | 9 -- 4 files changed, 53 insertions(+), 60 deletions(-) diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt index 7b7651777..ea1fbe4bf 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/api/entities/GearyEntity.kt @@ -17,7 +17,6 @@ import com.mineinabyss.geary.ecs.components.RelationComponent import com.mineinabyss.geary.ecs.engine.* import com.mineinabyss.geary.ecs.events.AddedComponent import kotlinx.serialization.Serializable -import org.koin.core.component.KoinComponent import kotlin.reflect.KClass import org.koin.core.component.get as koinGet @@ -30,7 +29,7 @@ import org.koin.core.component.get as koinGet @JvmInline @Suppress("NOTHING_TO_INLINE") public value class GearyEntity(public val id: GearyEntityId) : EngineScope { - //TODO with multiple accessors, remove and require each functino call has scope + //TODO This is a huge performance hit. Change when we get context support in 1.6.20. override val engine: Engine get() = koinGet() /** Gets the record associated with this entity or throws an error if it is no longer active on the koinGet(). */ public inline val record: Record get() = koinGet().getRecord(this) diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt index 965a08532..8ce81b000 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt @@ -17,8 +17,6 @@ import com.mineinabyss.geary.ecs.query.contains import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap import it.unimi.dsi.fastutil.longs.LongArrayList -import kotlinx.coroutines.newSingleThreadContext -import kotlinx.coroutines.sync.Mutex import org.koin.core.component.KoinComponent import org.koin.core.component.inject import java.util.* @@ -34,7 +32,7 @@ public data class Archetype( public val type: GearyType, public val id: Int ) : KoinComponent { - private val engine by inject() + private val engine: Engine by inject() /** The entity ids in this archetype. Indices are the same as [componentData]'s sub-lists. */ //TODO aim to make private @@ -165,14 +163,17 @@ public data class Archetype( * * @return The new [Record] to be associated with this entity from now on. */ - @Synchronized internal fun addEntityWithData( entity: GearyEntity, data: List ): Record { - ids.add(entity.id.toLong()) - componentData.forEachIndexed { i, compArray -> - compArray.add(data[i]) + synchronized(ids) { + ids.add(entity.id.toLong()) + } + synchronized(componentData) { + componentData.forEachIndexed { i, compArray -> + compArray.add(data[i]) + } } return Record.of(this, size - 1) } @@ -187,12 +188,11 @@ public data class Archetype( * * @see Engine.addComponentFor */ - @Synchronized internal fun addComponent( entity: GearyEntity, row: Int, component: GearyComponentId - ): Record? { + ): Record? = synchronized(ids) { // if already present in this archetype, stop here since we dont need to update any data if (contains(component)) return null @@ -212,7 +212,6 @@ public data class Archetype( * * @see Engine.setComponentFor */ - @Synchronized internal fun setComponent( entity: GearyEntity, row: Int, @@ -226,28 +225,30 @@ public data class Archetype( //if component was added but not set, remove the old component before adding this one val addId = dataComponent.withoutRole(HOLDS_DATA) - if (addId in type) { - val removedRecord = removeComponent(entity, row, addId)!! - return removedRecord.archetype.setComponent(entity, removedRecord.row, dataComponent, data) - } + synchronized(ids) { + if (addId in type) { + val removedRecord = removeComponent(entity, row, addId)!! + return removedRecord.archetype.setComponent(entity, removedRecord.row, dataComponent, data) + } - //If component already in this type, just update the data - val addIndex = indexOf(dataComponent) - if (addIndex != -1) { - componentData[addIndex][row] = data - return null - } + //If component already in this type, just update the data + val addIndex = indexOf(dataComponent) + if (addIndex != -1) { + componentData[addIndex][row] = data + return null + } - val moveTo = this + dataComponent - val newCompIndex = moveTo.dataHoldingType.indexOf(dataComponent) - val componentData = getComponents(row).apply { - //TODO this will throw an error if row changed when something else removed the entity from here. - // For now we try to move it as early as possible :s - removeEntity(row) - add(newCompIndex, data) - } + val moveTo = this + dataComponent + val newCompIndex = moveTo.dataHoldingType.indexOf(dataComponent) + val componentData = getComponents(row).apply { + //TODO this will throw an error if row changed when something else removed the entity from here. + // For now we try to move it as early as possible :s + removeEntity(row) + add(newCompIndex, data) + } - return moveTo.addEntityWithData(entity, componentData) + return moveTo.addEntityWithData(entity, componentData) + } } /** @@ -258,7 +259,6 @@ public data class Archetype( * * @see Engine.removeComponentFor */ - @Synchronized internal fun removeComponent( entity: GearyEntity, row: Int, @@ -271,13 +271,15 @@ public data class Archetype( val componentData = mutableListOf() val skipData = indexOf(component) - this.componentData.forEachIndexed { i, it -> - if (i != skipData) - componentData.add(it[row]) - } + synchronized(ids) { + this.componentData.forEachIndexed { i, it -> + if (i != skipData) + componentData.add(it[row]) + } - removeEntity(row) - return moveTo.addEntityWithData(entity, componentData) + removeEntity(row) + return moveTo.addEntityWithData(entity, componentData) + } } /** Gets all the components associated with an entity at a [row]. */ @@ -285,24 +287,26 @@ public data class Archetype( componentData.mapTo(arrayListOf()) { it[row] } /** Removes the entity at a [row] in this archetype, notifying running archetype iterators. */ - @Synchronized internal fun removeEntity(row: Int) { try { - val lastIndex = ids.lastIndex - val replacement = ids.getLong(lastIndex) - ids[row] = replacement + synchronized(ids) { + + val lastIndex = ids.lastIndex + val replacement = ids.getLong(lastIndex) + ids[row] = replacement - if (lastIndex != row) - componentData.forEach { it[row] = it.last() } + if (lastIndex != row) + componentData.forEach { it[row] = it.last() } - ids.removeLastOrNull() - componentData.forEach { it.removeLastOrNull() } + ids.removeLastOrNull() + componentData.forEach { it.removeLastOrNull() } - if (lastIndex != row) { - runningIterators.forEach { - it.addMovedRow(lastIndex, row) + if (lastIndex != row) { + runningIterators.forEach { + it.addMovedRow(lastIndex, row) + } + engine.setRecord(replacement.toGeary(), Record.of(this, row)) } - engine.setRecord(replacement.toGeary(), Record.of(this, row)) } } catch (e: IndexOutOfBoundsException) { throw IllegalStateException("Error while removing entity at row $row for archetype $this", e) diff --git a/platforms/papermc/plugin/build.gradle.kts b/platforms/papermc/plugin/build.gradle.kts index 99ec26509..dfe28d8c4 100644 --- a/platforms/papermc/plugin/build.gradle.kts +++ b/platforms/papermc/plugin/build.gradle.kts @@ -11,7 +11,6 @@ repositories { dependencies { // Shaded api(project(":geary-papermc-core")) - api(project(":geary-web-console")) // Other plugins compileOnly(gearylibs.plugman) diff --git a/platforms/papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt b/platforms/papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt index c222c84b2..dee4393ce 100644 --- a/platforms/papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt +++ b/platforms/papermc/plugin/src/main/kotlin/com/mineinabyss/geary/papermc/plugin/GearyPluginImpl.kt @@ -4,7 +4,6 @@ import com.mineinabyss.geary.api.addon.GearyLoadPhase.ENABLE import com.mineinabyss.geary.ecs.api.engine.Engine import com.mineinabyss.geary.ecs.api.systems.QueryManager import com.mineinabyss.geary.ecs.entities.UUID2GearyMap -import com.mineinabyss.geary.ecs.helpers.GearyKoinComponent import com.mineinabyss.geary.ecs.serialization.Formats import com.mineinabyss.geary.ecs.serialization.withSerialName import com.mineinabyss.geary.papermc.GearyConfig @@ -19,8 +18,6 @@ import com.mineinabyss.geary.papermc.listeners.GearyAttemptSpawnListener import com.mineinabyss.geary.papermc.store.FileSystemStore import com.mineinabyss.geary.papermc.store.GearyStore import com.mineinabyss.geary.prefabs.PrefabManager -import com.mineinabyss.geary.webconsole.GearyWebConsole -import com.mineinabyss.geary.webconsole.webConsole import com.mineinabyss.idofront.config.singleConfig import com.mineinabyss.idofront.config.startOrAppendKoin import com.mineinabyss.idofront.platforms.IdofrontPlatforms @@ -44,7 +41,6 @@ public class GearyPluginImpl : GearyPlugin() { saveDefaultConfig() reloadConfig() - val webConsole = GearyWebConsole() val engine = PaperMCEngine(this@GearyPluginImpl) val queryManager = QueryManager(engine) val bukkitEntity2Geary = BukkitEntity2Geary() @@ -54,7 +50,6 @@ public class GearyPluginImpl : GearyPlugin() { startOrAppendKoin(module { single { this@GearyPluginImpl } - single { webConsole } single { queryManager } single { engine } single { bukkitEntity2Geary } @@ -65,7 +60,6 @@ public class GearyPluginImpl : GearyPlugin() { }) engine.start() - webConsole.start() uuid2GearyMap.startTracking() bukkitEntity2Geary.startTracking() @@ -101,8 +95,5 @@ public class GearyPluginImpl : GearyPlugin() { override fun onDisable() { server.scheduler.cancelTasks(this) - GearyKoinComponent().apply { - webConsole.stop() - } } } From 0328ecbdbf021c786d0c7ccb0d924d7d2dd12af2 Mon Sep 17 00:00:00 2001 From: 0ffz Date: Thu, 27 Jan 2022 21:07:07 -0500 Subject: [PATCH 6/6] Fix build, temp fix for dokka until multiplatform setup --- .github/workflows/publish-packages.yml | 9 ++++++--- .../kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt | 1 + gradle.properties | 4 ++-- platforms/papermc/build.gradle.kts | 7 +------ settings.gradle.kts | 7 ++++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml index 1295f6aa2..7a20f9a9e 100644 --- a/.github/workflows/publish-packages.yml +++ b/.github/workflows/publish-packages.yml @@ -28,13 +28,16 @@ jobs: run: gradle build publish -PmineinabyssMavenUsername=${{ secrets.MAVEN_PUBLISH_USERNAME }} -PmineinabyssMavenPassword=${{ secrets.MAVEN_PUBLISH_PASSWORD }} - name: Generate Dokka - run: gradle dokkaHtmlMultiModule + # TODO figure out dokka for kotlin multiplatform +# run: gradle dokkaHtmlMultiModule + run: gradle geary-core:dokkaHtml - name: Publish documentation to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./build/dokka/htmlMultiModule +# publish_dir: ./build/dokka/htmlMultiModule + publish_dir: ./geary-core/build/dokka/html force_orphan: true - name: Get version from gradle @@ -51,4 +54,4 @@ jobs: prerelease: false automatic_release_tag: v${{ steps.extract_version.outputs.version }} files: | - platforms/geary-papermc-core/build/libs/*-all.jar + platforms/papermc/build/libs/*-all.jar diff --git a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt index 8ce81b000..c5999ee9a 100644 --- a/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt +++ b/geary-core/src/main/kotlin/com/mineinabyss/geary/ecs/engine/Archetype.kt @@ -36,6 +36,7 @@ public data class Archetype( /** The entity ids in this archetype. Indices are the same as [componentData]'s sub-lists. */ //TODO aim to make private + //TODO take a look at atomicfu for multiplatform support internal val ids: LongArrayList = LongArrayList() /** Component ids in the type that are to hold data */ diff --git a/gradle.properties b/gradle.properties index c9e6a82f9..c3d9a31dc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,8 @@ group=com.mineinabyss -version=0.13 +version=0.14 # Workaround for dokka builds failing on CI, see https://github.com/Kotlin/dokka/issues/1405 org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m -idofrontConventions=1.6.10-58 +idofrontConventions=1.6.10-63 kotlinVersion=1.6.10 serverVersion=1.17.1-R0.1-SNAPSHOT dokkaVersion=1.6.0 diff --git a/platforms/papermc/build.gradle.kts b/platforms/papermc/build.gradle.kts index 05ad23a1c..82494027d 100644 --- a/platforms/papermc/build.gradle.kts +++ b/platforms/papermc/build.gradle.kts @@ -7,6 +7,7 @@ plugins { repositories { mavenCentral() maven("https://jitpack.io") + maven("https://repo.mineinabyss.com/releases") } configurations { @@ -27,9 +28,3 @@ dependencies { // Shaded implementation(project(":geary-papermc-plugin")) } - -tasks { - shadowJar { - archiveBaseName.set("Geary") - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 90bc0f67a..4833d4e7c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -29,13 +29,15 @@ pluginManagement { } dependencyResolutionManagement { + val idofrontConventions: String by settings + repositories { - mavenLocal() + maven("https://repo.mineinabyss.com/releases") } versionCatalogs { create("libs") { - from("com.mineinabyss:catalog:1.6.10-DEV") + from("com.mineinabyss:catalog:$idofrontConventions") } create("gearylibs") { version("bimap-test", "1.2") @@ -68,4 +70,3 @@ file("./platforms/papermc") } includeBuild("geary-conventions") -includeBuild("../Idofront")