Add per compat project event listeners

[no changelog]
This commit is contained in:
Linnea Gräf
2024-09-01 22:21:19 +02:00
parent 816f80f862
commit 5ed74f2df4
20 changed files with 161 additions and 73 deletions

View File

@@ -6,10 +6,11 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import com.google.devtools.ksp.gradle.KspTaskJvm
import moe.nea.licenseextractificator.LicenseDiscoveryTask
import net.fabricmc.loom.LoomGradleExtension
import org.gradle.internal.extensions.stdlib.capitalized
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
@@ -102,6 +103,7 @@ fun createIsolatedSourceSet(name: String, path: String = "compat/$name"): Source
compatSourceSets.add(ss)
loom.createRemapConfigurations(ss)
val mainSS = sourceSets.main.get()
val upperName = ss.name.replaceFirstChar { it.uppercaseChar() }
configurations {
(ss.implementationConfigurationName) {
extendsFrom(getByName(mainSS.compileClasspathConfigurationName))
@@ -112,10 +114,15 @@ fun createIsolatedSourceSet(name: String, path: String = "compat/$name"): Source
(mainSS.runtimeOnlyConfigurationName) {
extendsFrom(getByName(ss.runtimeClasspathConfigurationName))
}
("ksp" + ss.name.replaceFirstChar { it.uppercaseChar() }) {
("ksp$upperName") {
extendsFrom(ksp.get())
}
}
afterEvaluate {
tasks.named("ksp${upperName}Kotlin", KspTaskJvm::class) {
this.options.add(SubpluginOption("apoption", "firmament.sourceset=${ss.name}"))
}
}
dependencies {
runtimeOnly(ss.output)
(ss.implementationConfigurationName)(sourceSets.main.get().output)

View File

@@ -7,16 +7,19 @@ import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class MixinPlugin implements IMixinConfigPlugin {
AutoDiscoveryPlugin autoDiscoveryPlugin = new AutoDiscoveryPlugin();
public static String mixinPackage;
@Override
public void onLoad(String mixinPackage) {
MixinExtrasBootstrap.init();
MixinPlugin.mixinPackage = mixinPackage;
autoDiscoveryPlugin.setMixinPackage(mixinPackage);
}
@@ -40,7 +43,8 @@ public class MixinPlugin implements IMixinConfigPlugin {
@Override
public List<String> getMixins() {
return autoDiscoveryPlugin.getMixins();
return autoDiscoveryPlugin.getMixins().stream().filter(it -> this.shouldApplyMixin(null, it))
.toList();
}
@Override
@@ -48,8 +52,10 @@ public class MixinPlugin implements IMixinConfigPlugin {
}
public static List<String> appliedMixins = new ArrayList<>();
@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
appliedMixins.add(mixinClassName);
}
}

View File

@@ -54,7 +54,8 @@ public class SectionBuilderRiser extends RiserUtils {
private void handle(ClassNode classNode) {
for (MethodNode method : classNode.methods) {
if (method.name.endsWith("$fabric-renderer-indigo$hookChunkBuildTessellate") &&
if ((method.name.endsWith("$fabric-renderer-indigo$hookBuildRenderBlock")
|| method.name.endsWith("$fabric-renderer-indigo$hookChunkBuildTessellate")) &&
method.name.startsWith("redirect$")) {
handleIndigo(method);
return;

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.commands
import com.mojang.brigadier.CommandDispatcher
@@ -9,6 +7,7 @@ import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
import net.minecraft.text.Text
import moe.nea.firmament.apis.UrsaManager
import moe.nea.firmament.events.CommandEvent
import moe.nea.firmament.events.FirmamentEventBus
import moe.nea.firmament.features.debug.PowerUserTools
import moe.nea.firmament.features.inventory.buttons.InventoryButtons
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
@@ -16,6 +15,7 @@ import moe.nea.firmament.features.inventory.storageoverlay.StorageOverviewScreen
import moe.nea.firmament.gui.config.AllConfigsGui
import moe.nea.firmament.gui.config.BooleanHandler
import moe.nea.firmament.gui.config.ManagedOption
import moe.nea.firmament.init.MixinPlugin
import moe.nea.firmament.repo.HypixelStaticData
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.FirmFormatters
@@ -201,7 +201,8 @@ fun firmamentCommand() = literal("firmament") {
thenLiteral("copyEntities") {
thenExecute {
val player = MC.player ?: return@thenExecute
player.world.getOtherEntities(player, player.boundingBox.expand(12.0)).forEach(PowerUserTools::showEntity)
player.world.getOtherEntities(player, player.boundingBox.expand(12.0))
.forEach(PowerUserTools::showEntity)
}
}
thenLiteral("callUrsa") {
@@ -213,6 +214,32 @@ fun firmamentCommand() = literal("firmament") {
}
}
}
thenLiteral("events") {
thenExecute {
source.sendFeedback(Text.translatable("firmament.event.start"))
FirmamentEventBus.allEventBuses.forEach { eventBus ->
source.sendFeedback(Text.translatable(
"firmament.event.bustype",
eventBus.eventType.typeName.removePrefix("moe.nea.firmament")))
eventBus.handlers.forEach { handler ->
source.sendFeedback(Text.translatable(
"firmament.event.handler",
handler.label))
}
}
}
}
thenLiteral("mixins") {
thenExecute {
source.sendFeedback(Text.translatable("firmament.mixins.start"))
MixinPlugin.appliedMixins
.map { it.removePrefix(MixinPlugin.mixinPackage) }
.forEach {
source.sendFeedback(Text.literal(" - ").withColor(0xD020F0)
.append(Text.literal(it).withColor(0xF6BA20)))
}
}
}
}
CommandEvent.SubCommand.publish(CommandEvent.SubCommand(this@literal))
}

View File

@@ -1,8 +1,7 @@
package moe.nea.firmament.events
import java.util.concurrent.CopyOnWriteArrayList
import org.apache.commons.lang3.reflect.TypeUtils
import moe.nea.firmament.Firmament
import moe.nea.firmament.util.MC
@@ -13,18 +12,31 @@ import moe.nea.firmament.util.MC
* Subscriptions may not necessarily be delivered in the order of registering.
*/
open class FirmamentEventBus<T : FirmamentEvent> {
companion object {
val allEventBuses = mutableListOf<FirmamentEventBus<*>>()
}
val eventType = TypeUtils.getTypeArguments(javaClass, FirmamentEventBus::class.java)!!.values.single()
init {
allEventBuses.add(this)
}
data class Handler<T>(
val invocation: (T) -> Unit, val receivesCancelled: Boolean,
var knownErrors: MutableSet<Class<*>> = mutableSetOf(),
val label: String,
)
private val toHandle: MutableList<Handler<T>> = CopyOnWriteArrayList()
fun subscribe(handle: (T) -> Unit) {
subscribe(false, handle)
val handlers: List<Handler<T>> get() = toHandle
fun subscribe(label: String, handle: (T) -> Unit) {
subscribe(false, label, handle)
}
fun subscribe(receivesCancelled: Boolean, handle: (T) -> Unit) {
toHandle.add(Handler(handle, receivesCancelled))
fun subscribe(receivesCancelled: Boolean, label: String, handle: (T) -> Unit) {
toHandle.add(Handler(handle, receivesCancelled, label = label))
}
fun publish(event: T): T {

View File

@@ -13,4 +13,5 @@ data class Subscription<T : FirmamentEvent>(
val owner: Any,
val invoke: (T) -> Unit,
val eventBus: FirmamentEventBus<T>,
val methodName: String,
)

View File

@@ -0,0 +1,25 @@
package moe.nea.firmament.events.subscription
import java.util.ServiceLoader
import kotlin.streams.asSequence
import moe.nea.firmament.Firmament
interface SubscriptionList {
fun provideSubscriptions(addSubscription: (Subscription<*>) -> Unit)
companion object {
val allLists by lazy {
ServiceLoader.load(SubscriptionList::class.java)
.stream()
.asSequence()
.mapNotNull {
kotlin.runCatching { it.get() }
.getOrElse { ex ->
Firmament.logger.error("Could not load subscriptions from ${it.type()}", ex)
null
}
}
.toList()
}
}
}

View File

@@ -1,14 +1,12 @@
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.events.subscription.SubscriptionList
import moe.nea.firmament.features.chat.AutoCompletions
import moe.nea.firmament.features.chat.ChatLinks
import moe.nea.firmament.features.chat.QuickCommands
@@ -88,13 +86,15 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
}
fun subscribeEvents() {
AllSubscriptions.provideSubscriptions {
SubscriptionList.allLists.forEach {
it.provideSubscriptions {
subscribeSingleEvent(it)
}
}
}
private fun <T : FirmamentEvent> subscribeSingleEvent(it: Subscription<T>) {
it.eventBus.subscribe(false, it.invoke)
it.eventBus.subscribe(false, "${it.owner.javaClass.simpleName}:${it.methodName}", it.invoke)
}
fun loadFeature(feature: FirmamentFeature) {

View File

@@ -3,6 +3,7 @@
package moe.nea.firmament.features.debug
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.TickEvent
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.util.TimeMark
@@ -25,14 +26,4 @@ object DebugView : FirmamentFeature {
}
}
fun recalculateDebugWidget() {
}
override fun onLoad() {
TickEvent.subscribe {
synchronized(this) {
recalculateDebugWidget()
}
}
}
}

View File

@@ -4,6 +4,7 @@ package moe.nea.firmament.features.debug
import net.minecraft.block.SkullBlock
import net.minecraft.block.entity.SkullBlockEntity
import net.minecraft.client.gui.screen.Screen
import net.minecraft.component.DataComponentTypes
import net.minecraft.entity.Entity
import net.minecraft.entity.LivingEntity
@@ -54,16 +55,17 @@ object PowerUserTools : FirmamentFeature {
}
var lastCopiedStackViewTime = false
override fun onLoad() {
TickEvent.subscribe {
@Subscribe
fun resetLastCopiedStack(event: TickEvent) {
if (!lastCopiedStackViewTime)
lastCopiedStack = null
lastCopiedStackViewTime = false
}
ScreenChangeEvent.subscribe {
@Subscribe
fun resetLastCopiedStackOnScreenChange(event: ScreenChangeEvent) {
lastCopiedStack = null
}
}
fun debugFormat(itemStack: ItemStack): Text {
return Text.literal(itemStack.skyBlockId?.toString() ?: itemStack.toString())

View File

@@ -1,14 +1,8 @@
package moe.nea.firmament.features.diana
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.AttackBlockEvent
import moe.nea.firmament.events.ParticleSpawnEvent
import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.events.SoundReceiveEvent
import moe.nea.firmament.events.UseBlockEvent
import moe.nea.firmament.events.WorldKeyboardEvent
import moe.nea.firmament.events.WorldReadyEvent
import moe.nea.firmament.events.WorldRenderLastEvent
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
@@ -22,13 +16,15 @@ object DianaWaypoints : FirmamentFeature {
val nearbyWaypoints by toggle("nearby-waypoints") { true }
}
override fun onLoad() {
UseBlockEvent.subscribe {
NearbyBurrowsSolver.onBlockClick(it.hitResult.blockPos)
}
AttackBlockEvent.subscribe {
NearbyBurrowsSolver.onBlockClick(it.blockPos)
@Subscribe
fun onBlockUse(event: UseBlockEvent) {
NearbyBurrowsSolver.onBlockClick(event.hitResult.blockPos)
}
@Subscribe
fun onBlockAttack(event: AttackBlockEvent) {
NearbyBurrowsSolver.onBlockClick(event.blockPos)
}
}

View File

@@ -168,7 +168,11 @@ object CustomBlockTextures {
}
private val sodiumReloadTask = runCatching {
Class.forName("moe.nea.firmament.compat.sodium.SodiumChunkReloader").getConstructor().newInstance() as Runnable
val r = Class.forName("moe.nea.firmament.compat.sodium.SodiumChunkReloader")
.getConstructor()
.newInstance() as Runnable
r.run()
r
}.getOrElse {
if (FabricLoader.getInstance().isModLoaded("sodium"))
logger.error("Could not create sodium chunk reloader")
@@ -192,7 +196,9 @@ object CustomBlockTextures {
@JvmStatic
fun getReplacement(block: BlockState, blockPos: BlockPos?): Replacement? {
if (isInFallback() && blockPos == null) return null
if (isInFallback() && blockPos == null) {
return null
}
val replacements = currentIslandReplacements?.lookup?.get(block.block) ?: return null
for (replacement in replacements) {
if (replacement.checks == null || matchesPosition(replacement, blockPos))

View File

@@ -37,7 +37,7 @@ abstract class MoulConfigHud(
init {
require(name.matches("^[a-z_/]+$".toRegex()))
HudRenderEvent.subscribe {
HudRenderEvent.subscribe("MoulConfigHud:render") {
if (!shouldRender()) return@subscribe
val renderContext = componentWrapper.createContext(it.context)
if (fragment == null)
@@ -50,7 +50,7 @@ abstract class MoulConfigHud(
fragment!!.root.render(renderContextTranslated)
it.context.matrices.pop()
}
FinalizeResourceManagerEvent.subscribe {
FinalizeResourceManagerEvent.subscribe("MoulConfigHud:finalizeResourceManager") {
MC.resourceManager.registerReloader(object : SynchronousResourceReloader {
override fun reload(manager: ResourceManager?) {
fragment = null

View File

@@ -19,7 +19,7 @@ object MC {
private val messageQueue = ConcurrentLinkedQueue<Text>()
init {
TickEvent.subscribe {
TickEvent.subscribe("MC:push") {
while (true) {
inGameHud.chatHud.addMessage(messageQueue.poll() ?: break)
}

View File

@@ -26,7 +26,7 @@ object SBData {
val isOnSkyblock get() = locraw?.gametype == "SKYBLOCK"
var lastProfileIdRequest = TimeMark.farPast()
fun init() {
ServerConnectedEvent.subscribe {
ServerConnectedEvent.subscribe("SBData:onServerConnected") {
HypixelModAPI.getInstance().subscribeToEventPacket(ClientboundLocationPacket::class.java)
}
HypixelModAPI.getInstance().createHandler(ClientboundLocationPacket::class.java) {
@@ -39,18 +39,18 @@ object SBData {
SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, null))
}
}
SkyblockServerUpdateEvent.subscribe {
SkyblockServerUpdateEvent.subscribe("SBData:sendProfileId") {
if (!hasReceivedProfile && isOnSkyblock && lastProfileIdRequest.passedTime() > 30.seconds) {
lastProfileIdRequest = TimeMark.now()
MC.sendServerCommand("profileid")
}
}
AllowChatEvent.subscribe { event ->
AllowChatEvent.subscribe("SBData:hideProfileSuggest") { event ->
if (event.unformattedString in profileSuggestTexts && lastProfileIdRequest.passedTime() < 5.seconds) {
event.cancel()
}
}
ProcessChatEvent.subscribe(receivesCancelled = true) { event ->
ProcessChatEvent.subscribe(receivesCancelled = true, "SBData:loadProfile") { event ->
val profileMatch = profileRegex.matchEntire(event.unformattedString)
if (profileMatch != null) {
try {

View File

@@ -57,7 +57,7 @@ object WarpUtil {
}
init {
ProcessChatEvent.subscribe {
ProcessChatEvent.subscribe("WarpUtil:processChat") {
if (it.unformattedString == "You haven't unlocked this fast travel destination!"
&& lastWarpAttempt.passedTime() < 2.seconds
) {

View File

@@ -24,7 +24,7 @@ private object InputHandler {
}
init {
HandledScreenKeyPressedEvent.subscribe { event ->
HandledScreenKeyPressedEvent.subscribe("Input:resumeAfterInput") { event ->
synchronized(InputHandler) {
val toRemove = activeContinuations.filter {
event.matches(it.keybind)

View File

@@ -56,7 +56,7 @@ interface IDataHolder<T> {
}
fun registerEvents() {
ScreenChangeEvent.subscribe { event ->
ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event ->
performSaves()
val p = MinecraftClient.getInstance().player
if (p != null) {

View File

@@ -20,6 +20,10 @@
"firmament.poweruser.entity.armor": "Entity Armor:",
"firmament.poweruser.entity.armor.item": " - %s",
"firmament.poweruser.entity.passengers": "%s Passengers",
"firmament.mixins.start": "Applied firmament mixins:",
"firmament.event.start": "Event Bus Readout:",
"firmament.event.bustype": " - %s:",
"firmament.event.handler": " * %s",
"firmament.config.all-configs": "- All Configs -",
"firmament.config.anniversary": "Anniversary Features",
"firmament.config.anniversary.shiny-pigs": "Shiny Pigs Tracker",

View File

@@ -1,4 +1,3 @@
package moe.nea.firmament.annotations.process
import com.google.auto.service.AutoService
@@ -16,23 +15,24 @@ 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,
val sourceSetName: String,
) : SymbolProcessor {
override fun finish() {
subscriptions.sort()
if (subscriptions.isEmpty()) return
val subscriptionSet = subscriptions.mapTo(mutableSetOf()) { it.parent.containingFile!! }
val dependencies = Dependencies(
aggregating = true,
*subscriptionSet.toTypedArray())
val generatedFileName = "AllSubscriptions${sourceSetName.replaceFirstChar { it.uppercaseChar() }}"
val subscriptionsFile =
codeGenerator
.createNewFile(dependencies, "moe.nea.firmament.annotations.generated", "AllSubscriptions")
.createNewFile(dependencies, "moe.nea.firmament.annotations.generated", generatedFileName)
.bufferedWriter()
subscriptionsFile.apply {
appendLine("// This file is @generated by SubscribeAnnotationProcessor")
@@ -44,8 +44,8 @@ class SubscribeAnnotationProcessor(
appendLine()
appendLine("import moe.nea.firmament.events.subscription.*")
appendLine()
appendLine("object AllSubscriptions {")
appendLine(" fun provideSubscriptions(addSubscription: (Subscription<*>) -> Unit) {")
appendLine("class $generatedFileName : SubscriptionList {")
appendLine(" override fun provideSubscriptions(addSubscription: (Subscription<*>) -> Unit) {")
for (subscription in subscriptions) {
val owner = subscription.parent.qualifiedName!!.asString()
val method = subscription.child.simpleName.asString()
@@ -53,12 +53,20 @@ class SubscribeAnnotationProcessor(
appendLine(" addSubscription(Subscription<$type>(")
appendLine(" ${owner},")
appendLine(" ${owner}::${method},")
appendLine(" ${type}))")
appendLine(" ${type},")
appendLine(" \"${method}\"))")
}
appendLine(" }")
appendLine("}")
}
subscriptionsFile.close()
val metaInf = codeGenerator.createNewFileByPath(
Dependencies(false),
"META-INF/services/moe.nea.firmament.events.subscription.SubscriptionList", extensionName = "")
.bufferedWriter()
metaInf.append("moe.nea.firmament.annotations.generated.")
metaInf.appendLine(generatedFileName)
metaInf.close()
}
data class Subscription(
@@ -121,6 +129,8 @@ class SubscribeAnnotationProcessor(
@AutoService(SymbolProcessorProvider::class)
class SubscribeAnnotationProcessorProvider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return SubscribeAnnotationProcessor(environment.logger, environment.codeGenerator)
return SubscribeAnnotationProcessor(environment.logger,
environment.codeGenerator,
environment.options["firmament.sourceset"] ?: "main")
}
}