Add @Subscribe annotation
[no changelog]
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,6 +8,7 @@
|
||||
/build/
|
||||
/buildSrc/.gradle
|
||||
/buildSrc/build/
|
||||
/*/build
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
plugins {
|
||||
java
|
||||
`maven-publish`
|
||||
id("com.google.devtools.ksp") version "1.9.23-1.0.20"
|
||||
kotlin("jvm") version "1.9.23"
|
||||
kotlin("plugin.serialization") version "1.9.23"
|
||||
// id("com.bnorm.power.kotlin-power-assert") version "0.13.0"
|
||||
@@ -170,6 +171,9 @@ dependencies {
|
||||
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
|
||||
|
||||
implementation(project(":symbols"))
|
||||
ksp(project(":symbols"))
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
@@ -193,8 +197,8 @@ loom {
|
||||
parseEnvFile(file(".env")).forEach { (t, u) ->
|
||||
environmentVariable(t, u)
|
||||
}
|
||||
parseEnvFile(file(".properties")).forEach{ (t, u) ->
|
||||
property(t,u)
|
||||
parseEnvFile(file(".properties")).forEach { (t, u) ->
|
||||
property(t, u)
|
||||
}
|
||||
vmArg("-ea")
|
||||
vmArg("-XX:+AllowEnhancedClassRedefinition")
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
// SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||
//
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
@@ -28,3 +32,4 @@ pluginManagement {
|
||||
|
||||
rootProject.name = "Firmament"
|
||||
|
||||
include("symbols")
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package moe.nea.firmament.events.subscription
|
||||
|
||||
import moe.nea.firmament.events.FirmamentEvent
|
||||
import moe.nea.firmament.events.FirmamentEventBus
|
||||
|
||||
interface SubscriptionOwner
|
||||
|
||||
data class Subscription<T : FirmamentEvent>(
|
||||
val owner: SubscriptionOwner,
|
||||
val invoke: (T) -> Unit,
|
||||
val eventBus: FirmamentEventBus<T>,
|
||||
)
|
||||
@@ -10,7 +10,10 @@ package moe.nea.firmament.features
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.serializer
|
||||
import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.annotations.generated.AllSubscriptions
|
||||
import moe.nea.firmament.events.FeaturesInitializedEvent
|
||||
import moe.nea.firmament.events.FirmamentEvent
|
||||
import moe.nea.firmament.events.subscription.Subscription
|
||||
import moe.nea.firmament.features.chat.AutoCompletions
|
||||
import moe.nea.firmament.features.chat.ChatLinks
|
||||
import moe.nea.firmament.features.chat.QuickCommands
|
||||
@@ -80,11 +83,26 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
|
||||
loadFeature(DebugView)
|
||||
}
|
||||
allFeatures.forEach { it.config }
|
||||
subscribeEvents()
|
||||
FeaturesInitializedEvent.publish(FeaturesInitializedEvent(allFeatures.toList()))
|
||||
hasAutoloaded = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeEvents() {
|
||||
AllSubscriptions.provideSubscriptions {
|
||||
subscribeSingleEvent(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : FirmamentEvent> subscribeSingleEvent(it: Subscription<T>) {
|
||||
if (it.owner in features.values) { // TODO: better check here, somehow. probably implement some interface method
|
||||
it.eventBus.subscribe(false, it.invoke) // TODO: pass through receivesCancelled from the annotation
|
||||
} else {
|
||||
Firmament.logger.error("Ignoring event listener for ${it.eventBus} in ${it.owner}")
|
||||
}
|
||||
}
|
||||
|
||||
fun loadFeature(feature: FirmamentFeature) {
|
||||
synchronized(features) {
|
||||
if (feature.identifier in features) {
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package moe.nea.firmament.features
|
||||
|
||||
import moe.nea.firmament.events.subscription.SubscriptionOwner
|
||||
import moe.nea.firmament.gui.config.ManagedConfig
|
||||
|
||||
interface FirmamentFeature {
|
||||
interface FirmamentFeature : SubscriptionOwner {
|
||||
val identifier: String
|
||||
val defaultEnabled: Boolean
|
||||
get() = true
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
@@ -7,6 +8,7 @@
|
||||
package moe.nea.firmament.features.inventory
|
||||
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.ItemTooltipEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
import moe.nea.firmament.gui.config.ManagedConfig
|
||||
@@ -26,9 +28,12 @@ object PriceData : FirmamentFeature {
|
||||
override val config get() = TConfig
|
||||
|
||||
override fun onLoad() {
|
||||
ItemTooltipEvent.subscribe {
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun function(it: ItemTooltipEvent) {
|
||||
if (!TConfig.tooltipEnabled && !TConfig.enableKeybinding.isPressed()) {
|
||||
return@subscribe
|
||||
return
|
||||
}
|
||||
val sbId = it.stack.skyBlockId
|
||||
val bazaarData = HypixelStaticData.bazaarData[sbId]
|
||||
@@ -36,17 +41,19 @@ object PriceData : FirmamentFeature {
|
||||
if (bazaarData != null) {
|
||||
it.lines.add(Text.literal(""))
|
||||
it.lines.add(
|
||||
Text.stringifiedTranslatable("firmament.tooltip.bazaar.sell-order", FirmFormatters.formatCurrency(bazaarData.quickStatus.sellPrice, 1))
|
||||
Text.stringifiedTranslatable("firmament.tooltip.bazaar.sell-order",
|
||||
FirmFormatters.formatCurrency(bazaarData.quickStatus.sellPrice, 1))
|
||||
)
|
||||
it.lines.add(
|
||||
Text.stringifiedTranslatable("firmament.tooltip.bazaar.buy-order", FirmFormatters.formatCurrency(bazaarData.quickStatus.buyPrice, 1))
|
||||
Text.stringifiedTranslatable("firmament.tooltip.bazaar.buy-order",
|
||||
FirmFormatters.formatCurrency(bazaarData.quickStatus.buyPrice, 1))
|
||||
)
|
||||
} else if (lowestBin != null) {
|
||||
it.lines.add(Text.literal(""))
|
||||
it.lines.add(
|
||||
Text.stringifiedTranslatable("firmament.tooltip.ah.lowestbin", FirmFormatters.formatCurrency(lowestBin, 1))
|
||||
Text.stringifiedTranslatable("firmament.tooltip.ah.lowestbin",
|
||||
FirmFormatters.formatCurrency(lowestBin, 1))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.screen.GenericContainerScreenHandler
|
||||
import net.minecraft.screen.slot.SlotActionType
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
|
||||
import moe.nea.firmament.events.IsSlotProtectedEvent
|
||||
import moe.nea.firmament.events.SlotRenderEvents
|
||||
@@ -166,7 +167,10 @@ object SlotLocking : FirmamentFeature {
|
||||
event.protectSilent()
|
||||
}
|
||||
}
|
||||
SlotRenderEvents.After.subscribe {
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun function(it: SlotRenderEvents.After) {
|
||||
val isSlotLocked = it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())
|
||||
val isUUIDLocked = (it.slot.stack?.skyblockUUID) in (lockedUUIDs ?: setOf())
|
||||
if (isSlotLocked || isUUIDLocked) {
|
||||
@@ -190,5 +194,4 @@ object SlotLocking : FirmamentFeature {
|
||||
RenderSystem.enableDepthTest()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
symbols/build.gradle.kts
Normal file
19
symbols/build.gradle.kts
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("com.google.devtools.ksp")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
ksp("dev.zacsweers.autoservice:auto-service-ksp:1.1.0")
|
||||
implementation("com.google.auto.service:auto-service-annotations:1.1.1")
|
||||
implementation("com.google.devtools.ksp:symbol-processing-api:1.9.23-1.0.20")
|
||||
}
|
||||
12
symbols/src/main/kotlin/Subscribe.kt
Normal file
12
symbols/src/main/kotlin/Subscribe.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package moe.nea.firmament.annotations
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class Subscribe
|
||||
|
||||
116
symbols/src/main/kotlin/process/SubscribeAnnotationProcessor.kt
Normal file
116
symbols/src/main/kotlin/process/SubscribeAnnotationProcessor.kt
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package moe.nea.firmament.annotations.process
|
||||
|
||||
import com.google.auto.service.AutoService
|
||||
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.processing.SymbolProcessorEnvironment
|
||||
import com.google.devtools.ksp.processing.SymbolProcessorProvider
|
||||
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.symbol.KSFunctionDeclaration
|
||||
import com.google.devtools.ksp.symbol.KSType
|
||||
import com.google.devtools.ksp.symbol.Nullability
|
||||
import com.google.devtools.ksp.validate
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
|
||||
class SubscribeAnnotationProcessor(
|
||||
val logger: KSPLogger,
|
||||
val codeGenerator: CodeGenerator,
|
||||
) : SymbolProcessor {
|
||||
override fun finish() {
|
||||
val dependencies = Dependencies(
|
||||
aggregating = true,
|
||||
*subscriptions.mapTo(mutableSetOf()) { it.parent.containingFile!! }.toTypedArray())
|
||||
val subscriptionsFile =
|
||||
codeGenerator
|
||||
.createNewFile(dependencies, "moe.nea.firmament.annotations.generated", "AllSubscriptions")
|
||||
.bufferedWriter()
|
||||
subscriptionsFile.apply {
|
||||
appendLine("// This file is @generated by SubscribeAnnotationProcessor at ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(
|
||||
Date())}")
|
||||
appendLine("// Do not edit")
|
||||
appendLine("package moe.nea.firmament.annotations.generated")
|
||||
appendLine()
|
||||
appendLine("import moe.nea.firmament.events.subscription.*")
|
||||
appendLine()
|
||||
appendLine("object AllSubscriptions {")
|
||||
appendLine(" fun provideSubscriptions(addSubscription: (Subscription<*>) -> Unit) {")
|
||||
for (subscription in subscriptions) {
|
||||
val owner = subscription.parent.qualifiedName!!.asString()
|
||||
val method = subscription.child.simpleName.asString()
|
||||
val type = subscription.type.declaration.qualifiedName!!.asString()
|
||||
appendLine(" addSubscription(Subscription<$type>(")
|
||||
appendLine(" ${owner},")
|
||||
appendLine(" ${owner}::${method},")
|
||||
appendLine(" ${type}))")
|
||||
}
|
||||
appendLine(" }")
|
||||
appendLine("}")
|
||||
}
|
||||
subscriptionsFile.close()
|
||||
}
|
||||
|
||||
data class Subscription(
|
||||
val parent: KSClassDeclaration,
|
||||
val child: KSFunctionDeclaration,
|
||||
val type: KSType,
|
||||
)
|
||||
|
||||
val subscriptions = mutableListOf<Subscription>()
|
||||
|
||||
fun processCandidates(list: List<KSAnnotated>) {
|
||||
for (element in list) {
|
||||
if (element !is KSFunctionDeclaration) {
|
||||
logger.error("@Subscribe annotation on a not-function", element)
|
||||
continue
|
||||
}
|
||||
if (element.isAbstract) {
|
||||
logger.error("@Subscribe annotation on an abstract function", element)
|
||||
continue
|
||||
}
|
||||
val parent = element.parentDeclaration
|
||||
if (parent !is KSClassDeclaration || parent.isCompanionObject || parent.classKind != ClassKind.OBJECT) {
|
||||
logger.error("@Subscribe on a non-object", element)
|
||||
continue
|
||||
}
|
||||
val param = element.parameters.singleOrNull()
|
||||
if (param == null) {
|
||||
logger.error("@Subscribe annotated functions need to take exactly one parameter", element)
|
||||
continue
|
||||
}
|
||||
val type = param.type.resolve()
|
||||
if (type.nullability != Nullability.NOT_NULL) {
|
||||
logger.error("@Subscribe annotated functions cannot take a nullable event", element)
|
||||
continue
|
||||
}
|
||||
subscriptions.add(Subscription(parent, element, type))
|
||||
}
|
||||
}
|
||||
|
||||
override fun process(resolver: Resolver): List<KSAnnotated> {
|
||||
val candidates = resolver.getSymbolsWithAnnotation(Subscribe::class.qualifiedName!!).toList()
|
||||
val valid = candidates.filter { it.validate() }
|
||||
val invalid = candidates.filter { !it.validate() }
|
||||
processCandidates(valid)
|
||||
return invalid
|
||||
}
|
||||
}
|
||||
|
||||
@AutoService(SymbolProcessorProvider::class)
|
||||
class SubscribeAnnotationProcessorProvider : SymbolProcessorProvider {
|
||||
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
|
||||
return SubscribeAnnotationProcessor(environment.logger, environment.codeGenerator)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user