Skip to content

Commit

Permalink
Finalizing addon system, figuring out I/O on multiplatform
Browse files Browse the repository at this point in the history
  • Loading branch information
0ffz committed Dec 23, 2022
1 parent 80e5841 commit 11e80f1
Show file tree
Hide file tree
Showing 30 changed files with 345 additions and 367 deletions.
1 change: 1 addition & 0 deletions geary-autoscan/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ dependencies {
implementation("com.mineinabyss:ding:1.0.0")
compileOnly(libs.idofront.autoscan)
compileOnly(project(":geary-core"))
compileOnly(project(":geary-serialization"))
// compileOnly(project(":geary-prefabs"))
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.mineinabyss.geary.autoscan

import com.mineinabyss.ding.DI
import com.mineinabyss.geary.addons.GearyPhase
import com.mineinabyss.geary.addons.Namespaced
import com.mineinabyss.geary.addons.dsl.GearyAddon
import com.mineinabyss.geary.addons.dsl.GearyAddonWithDefault
import com.mineinabyss.geary.addons.dsl.GearyDSL
import com.mineinabyss.geary.modules.geary
import com.mineinabyss.geary.systems.System
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance

val autoScanner by DI.observe<AutoScanner>()

interface AutoScanner {
val scannedComponents: MutableSet<KClass<*>>
val scannedSystems: MutableSet<KClass<*>>

fun installSystems()

companion object Addon : GearyAddonWithDefault<AutoScanner> {
override fun default() = object : AutoScanner {
private val logger = geary.logger
override val scannedComponents = mutableSetOf<KClass<*>>()
override val scannedSystems = mutableSetOf<KClass<*>>()

override fun installSystems() {
scannedSystems.asSequence()
.mapNotNull { it.objectInstance ?: runCatching { it.createInstance() }.getOrNull() }
.filterIsInstance<System>()
.onEach { geary.systems.add(it) }
.map { it::class.simpleName }
.joinToString()
.let { logger.i("Autoscan loaded singleton systems: $it") }
}
}

override fun AutoScanner.install() {
geary.pipeline.intercept(GearyPhase.INIT_SYSTEMS) {
installSystems()
}
}
}
}

@GearyDSL
fun Namespaced.autoscan(vararg limitToPackages: String, configure: AutoScannerDSL.() -> Unit) =
gearyConf.install(AutoScanner).also { AutoScannerDSL(this, limitToPackages.toList()).configure() }
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.mineinabyss.geary.autoscan

import com.mineinabyss.geary.addons.Namespaced
import com.mineinabyss.geary.datatypes.Component
import com.mineinabyss.geary.modules.geary
import com.mineinabyss.geary.serialization.serialization
import com.mineinabyss.geary.systems.System
import kotlinx.serialization.*
import kotlinx.serialization.modules.PolymorphicModuleBuilder
import org.reflections.Reflections
import org.reflections.util.ClasspathHelper
import org.reflections.util.ConfigurationBuilder
import kotlin.reflect.KClass
import kotlin.reflect.full.hasAnnotation
import kotlin.reflect.full.isSubclassOf

class AutoScannerDSL(
val namespaced: Namespaced,
val limitTo: List<String>
) {
val logger = geary.logger

private val reflections: Reflections by lazy {
Reflections(
ConfigurationBuilder()
.addClassLoader(namespaced.currentClass.java.classLoader)
.apply {
limitTo.forEach { pkg ->
addUrls(ClasspathHelper.forPackage(pkg, namespaced.currentClass.java.classLoader))
}
}
)
}

/**
* Automatically scans for all annotated components
*
* @see autoScanComponents
* @see autoScanSystems
*/
fun all() {
components()
systems()
}

/**
* Registers serializers for [Component]s.
*
* @see AutoScanner
*/
fun components() {
val scanned = reflections
.getTypesAnnotatedWith(Serializable::class.java)
.asSequence()
.map { it.kotlin }
.filter { !it.hasAnnotation<ExcludeAutoScan>() }

geary {
namespaced.serialization {
components {
scanned.forEach { component(it) }
}
}
}
logger.i("Autoscan found components: ${scanned.joinToString { it.simpleName!! }}")

autoScanner.scannedComponents += scanned
}

/**
* Registers any systems (including event listeners) that are annotated with [AutoScanner].
*
* Supports singletons or classes with no constructor parameters.
*
* @see AutoScanner
*/
fun systems() {
val scanned = reflections.getTypesAnnotatedWith(AutoScan::class.java)
.asSequence()
.map { it.kotlin }
.filter { !it.hasAnnotation<ExcludeAutoScan>() && it.isSubclassOf(System::class) }

autoScanner.scannedSystems += scanned
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.mineinabyss.geary.addons

import com.mineinabyss.geary.addons.dsl.GearyDSL
import com.mineinabyss.geary.modules.GearyConfiguration
import com.mineinabyss.geary.modules.GearyModule
import kotlin.reflect.KClass

class Namespaced(val namespace: String)
@GearyDSL
class Namespaced(val namespace: String, val currentClass: KClass<*>, val gearyConf: GearyConfiguration)

Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import kotlinx.serialization.modules.PolymorphicModuleBuilder
import kotlin.reflect.KClass

/** The polymorphic builder scope that allows registering subclasses. */
typealias SerializerRegistry<T> = PolymorphicModuleBuilder<T>.(kClass: KClass<T>, serializer: KSerializer<T>?) -> Boolean
typealias SerializerRegistry<T> = PolymorphicModuleBuilder<T>.(kClass: KClass<T>, serializer: KSerializer<T>?) -> Unit
Original file line number Diff line number Diff line change
@@ -1,49 +1,9 @@
package com.mineinabyss.geary.addons.dsl

import com.mineinabyss.geary.modules.GearyModule

/**
* The entry point for other plugins to hook into Geary. Allows registering serializable components, systems, actions,
* and more.
*/
//@GearyDSLMarker
//class GearyAddon(
// val namespace: String,
// val classLoader: ClassLoader
//) : GearyDSL {
//
// override fun system(system: GearySystem) {
// geary.systems.add(system)
// }
//
// override fun systems(vararg systems: GearySystem) {
// systems.forEach { system(it) }
// }
//
// override fun serialization(init: SerializationAddon.() -> Unit) = on(GearyLoadPhase.REGISTER_SERIALIZERS) {
// SerializationAddon(this@GearyAddon).init()
// }
//
// override fun formats(init: Formats.(SerializersModule) -> Unit) = on(GearyLoadPhase.REGISTER_FORMATS) {
// geary.formats.init(geary.serializers.module)
// }
//
// /**
// * 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
// * }
// * ```
// */
// override fun on(phase: GearyLoadPhase, run: () -> Unit) {
// addons.manager.add(phase, run)
// }
//}
interface GearyAddon<Module, Conf> {
interface GearyAddonWithDefault<Module>: GearyAddon<Module> {
fun default(): Module
fun Module.install(geary: GearyModule)
}

interface GearyAddon<Module> {
fun Module.install()
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ package com.mineinabyss.geary.addons.dsl
*/
@DslMarker
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPEALIAS, AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
annotation class GearyDSLMarker
annotation class GearyDSL
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,6 @@ fun componentId(kClass: KClass<out ComponentId>): Nothing =
/** Gets the [ComponentInfo] component from a component's id. */
fun ComponentId.getComponentInfo(): ComponentInfo? =
this.toGeary().get()

fun systems(vararg systems: GearySystem): List<Deferred<Unit>> {
return systems.map { geary.engine.async { geary.systems.add(it) } }
}

//@ExperimentalAsyncGearyAPI
//public inline fun <T> runSafely(
// scope: CoroutineScope = globalContext.engine,
Expand Down
Loading

0 comments on commit 11e80f1

Please sign in to comment.