diff options
author | CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> | 2024-06-01 20:47:08 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-01 12:47:08 +0200 |
commit | a20da5a79b5b05839862c8e8fd165b18368729c1 (patch) | |
tree | ef0b258d90d839867eba8c002f02e1c823b049ef | |
parent | 2698b9d13de081be2e72e63faa213a74cafb6a6b (diff) | |
download | skyhanni-a20da5a79b5b05839862c8e8fd165b18368729c1.tar.gz skyhanni-a20da5a79b5b05839862c8e8fd165b18368729c1.tar.bz2 skyhanni-a20da5a79b5b05839862c8e8fd165b18368729c1.zip |
Backend: Auto load annotation (#1904)
Co-authored-by: Brady <thatgravyboat@gmail.com>
11 files changed, 144 insertions, 4 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6588b9a95..c66c048f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,6 +59,9 @@ format like "- #821" to illustrate the dependency. - All new classes should be written in Kotlin, with a few exceptions: - Config files in `at.hannibal2.skyhanni.config.features` - Mixin classes in `at.hannibal2.skyhanni.mixins.transformers` +- New features should be made in Kotlin objects unless there is a specific reason for it not to. + - If the feature needs to use forge events or a repo pattern, annotate it with `@SkyHanniModule` + - This will automatically register it to the forge event bus and load the repo patterns - Avoid using deprecated functions. - These functions are marked for removal in future versions. - If you're unsure why a function is deprecated or how to replace it, please ask for guidance. diff --git a/annotation-processors/build.gradle.kts b/annotation-processors/build.gradle.kts new file mode 100644 index 000000000..c091ba6e3 --- /dev/null +++ b/annotation-processors/build.gradle.kts @@ -0,0 +1,27 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + idea + kotlin("jvm") + java +} + +repositories { + mavenCentral() +} + +dependencies { + implementation(kotlin("stdlib-jdk8")) + implementation("com.google.devtools.ksp:symbol-processing-api:1.8.0-1.0.8") +} + +tasks.withType<JavaCompile> { + if (JavaVersion.current().isJava9Compatible) { + options.release.set(8) + } +} + +val compileKotlin: KotlinCompile by tasks +compileKotlin.kotlinOptions { + jvmTarget = "1.8" +} diff --git a/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/ModuleProcessor.kt b/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/ModuleProcessor.kt new file mode 100644 index 000000000..bc7d262b4 --- /dev/null +++ b/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/ModuleProcessor.kt @@ -0,0 +1,68 @@ +package at.hannibal2.skyhanni.skyhannimodule + +import com.google.devtools.ksp.processing.CodeGenerator +import com.google.devtools.ksp.processing.Dependencies +import com.google.devtools.ksp.processing.KSPLogger +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.processing.SymbolProcessor +import com.google.devtools.ksp.symbol.ClassKind +import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.validate +import java.io.OutputStreamWriter + +class ModuleProcessor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) : SymbolProcessor { + + override fun process(resolver: Resolver): List<KSAnnotated> { + + val symbols = resolver.getSymbolsWithAnnotation(SkyHanniModule::class.qualifiedName!!).toList() + val validSymbols = symbols.mapNotNull { validateSymbol(it) } + + if (validSymbols.isNotEmpty()) { + generateFile(validSymbols) + } + + return emptyList() + } + + private fun validateSymbol(symbol: KSAnnotated): KSClassDeclaration? { + if (!symbol.validate()) { + logger.warn("Symbol is not valid: $symbol") + return null + } + + if (symbol !is KSClassDeclaration) { + logger.error("@SkyHanniModule is only valid on class declarations", symbol) + return null + } + + if (symbol.classKind != ClassKind.OBJECT) { + logger.error("@SkyHanniModule is only valid on kotlin objects", symbol) + return null + } + + return symbol + } + + private fun generateFile(symbols: List<KSClassDeclaration>) { + val dependencies = symbols.mapNotNull { it.containingFile }.toTypedArray() + val deps = Dependencies(true, *dependencies) + + val file = codeGenerator.createNewFile(deps, "at.hannibal2.skyhanni.skyhannimodule", "LoadedModules") + + OutputStreamWriter(file).use { + it.write("package at.hannibal2.skyhanni.skyhannimodule\n\n") + it.write("object LoadedModules {\n") + it.write(" val modules: List<Any> = listOf(\n") + + symbols.forEach { symbol -> + it.write(" ${symbol.qualifiedName!!.asString()},\n") + } + + it.write(" )\n") + it.write("}\n") + } + + logger.warn("Generated LoadedModules file with ${symbols.size} modules") + } +} diff --git a/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/ModuleProvider.kt b/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/ModuleProvider.kt new file mode 100644 index 000000000..47d03655f --- /dev/null +++ b/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/ModuleProvider.kt @@ -0,0 +1,11 @@ +package at.hannibal2.skyhanni.skyhannimodule + +import com.google.devtools.ksp.processing.SymbolProcessor +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.google.devtools.ksp.processing.SymbolProcessorProvider + +class ModuleProvider : SymbolProcessorProvider { + override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { + return ModuleProcessor(environment.codeGenerator, environment.logger) + } +} diff --git a/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/SkyHanniModule.kt b/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/SkyHanniModule.kt new file mode 100644 index 000000000..cb6b0eae4 --- /dev/null +++ b/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/SkyHanniModule.kt @@ -0,0 +1,5 @@ +package at.hannibal2.skyhanni.skyhannimodule + +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.SOURCE) +annotation class SkyHanniModule diff --git a/annotation-processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/annotation-processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider new file mode 100644 index 000000000..5f0d42dc4 --- /dev/null +++ b/annotation-processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider @@ -0,0 +1 @@ +at.hannibal2.skyhanni.skyhannimodule.ModuleProvider diff --git a/build.gradle.kts b/build.gradle.kts index 051bcc4f9..b481a39cf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,6 +11,7 @@ plugins { kotlin("jvm") version "1.9.0" id("com.bnorm.power.kotlin-power-assert") version "0.13.0" `maven-publish` + id("com.google.devtools.ksp") version "1.9.0-1.0.13" id("moe.nea.shot") version "1.0.0" } @@ -90,6 +91,8 @@ dependencies { headlessLwjgl(libs.headlessLwjgl) + compileOnly(ksp(project(":annotation-processors"))!!) + shadowImpl("org.spongepowered:mixin:0.7.11-SNAPSHOT") { isTransitive = false } @@ -129,6 +132,11 @@ dependencies { implementation("net.hypixel:mod-api:0.3.1") } + +ksp { + arg("symbolProcessor", "at.hannibal2.skyhanni.loadmodule.LoadModuleProvider") +} + configurations.getByName("minecraftNamed").dependencies.forEach { shot.applyTo(it as HasConfigurableAttributes<*>) } @@ -147,6 +155,12 @@ kotlin { enableLanguageFeature("BreakContinueInInlineLambdas") } } + sourceSets.main { + kotlin.srcDir("build/generated/ksp/main/kotlin") + } + sourceSets.test { + kotlin.srcDir("build/generated/ksp/test/kotlin") + } } // Minecraft configuration: diff --git a/gradle.properties b/gradle.properties index 065574755..16cc55dfa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,5 @@ loom.platform=forge -org.gradle.jvmargs=-Xmx2g
\ No newline at end of file +org.gradle.jvmargs=-Xmx2g +org.gradle.parallel=true +org.gradle.caching=true +kotlin.incremental.useClasspathSnapshot=true diff --git a/settings.gradle.kts b/settings.gradle.kts index 12734a34a..8bd4de72f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -23,4 +23,5 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version("0.6.0") } +include("annotation-processors") rootProject.name = "SkyHanni" diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 5d1bb52ad..6fd2154e8 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -14,7 +14,6 @@ import at.hannibal2.skyhanni.data.ActionBarStatsData import at.hannibal2.skyhanni.data.BitsAPI import at.hannibal2.skyhanni.data.BlockData import at.hannibal2.skyhanni.data.BossbarData -import at.hannibal2.skyhanni.data.ChatManager import at.hannibal2.skyhanni.data.CropAccessoryData import at.hannibal2.skyhanni.data.EntityData import at.hannibal2.skyhanni.data.EntityMovementData @@ -453,6 +452,7 @@ import at.hannibal2.skyhanni.features.stranded.HighlightPlaceableNpcs import at.hannibal2.skyhanni.features.summonings.SummoningMobManager import at.hannibal2.skyhanni.features.summonings.SummoningSoulsName import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper +import at.hannibal2.skyhanni.skyhannimodule.LoadedModules import at.hannibal2.skyhanni.test.HighlightMissingRepoItems import at.hannibal2.skyhanni.test.PacketTest import at.hannibal2.skyhanni.test.ParkourWaypointSaver @@ -512,9 +512,10 @@ class SkyHanniMod { HotswapSupport.load() - // data loadModule(this) - loadModule(ChatManager) + LoadedModules.modules.forEach { loadModule(it) } + + // data loadModule(PlayerChatManager()) loadModule(PlayerNameFormatter()) loadModule(HypixelData()) @@ -1007,9 +1008,13 @@ class SkyHanniMod { } catch (e: Exception) { Exception("Error reading repo data", e).printStackTrace() } + loadedClasses.clear() } + private val loadedClasses = mutableSetOf<Any>() + fun loadModule(obj: Any) { + if (!loadedClasses.add(obj.javaClass.name)) throw IllegalStateException("Module ${obj.javaClass.name} is already loaded") modules.add(obj) MinecraftForge.EVENT_BUS.register(obj) } diff --git a/src/main/java/at/hannibal2/skyhanni/data/ChatManager.kt b/src/main/java/at/hannibal2/skyhanni/data/ChatManager.kt index 112c29f17..ef032f6fc 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/ChatManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/ChatManager.kt @@ -5,6 +5,7 @@ import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.MessageSendToServerEvent import at.hannibal2.skyhanni.events.PacketEvent import at.hannibal2.skyhanni.features.chat.ChatFilterGui +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.IdentityCharacteristics import at.hannibal2.skyhanni.utils.LorenzLogger @@ -26,6 +27,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.relauncher.ReflectionHelper import java.lang.invoke.MethodHandles +@SkyHanniModule object ChatManager { private val loggerAll = LorenzLogger("chat/all") |