From 4308a09f8929da42cab420d7254c0981d74bd651 Mon Sep 17 00:00:00 2001
From: Linnea Gräf <nea@nea.moe>
Date: Sat, 26 Oct 2024 17:26:37 +0200
Subject: Move explosive enhancment into isolation

[no changelog]
---
 .../kotlin/features/fixes/CompatibliltyFeatures.kt | 70 ++++++++++------------
 src/main/kotlin/util/compatloader/CompatLoader.kt  | 47 +++++++++++++++
 2 files changed, 77 insertions(+), 40 deletions(-)
 create mode 100644 src/main/kotlin/util/compatloader/CompatLoader.kt

(limited to 'src/main/kotlin')

diff --git a/src/main/kotlin/features/fixes/CompatibliltyFeatures.kt b/src/main/kotlin/features/fixes/CompatibliltyFeatures.kt
index fa9cdda..76f6ed4 100644
--- a/src/main/kotlin/features/fixes/CompatibliltyFeatures.kt
+++ b/src/main/kotlin/features/fixes/CompatibliltyFeatures.kt
@@ -1,51 +1,41 @@
-
-
 package moe.nea.firmament.features.fixes
 
-import net.fabricmc.loader.api.FabricLoader
-import net.superkat.explosiveenhancement.api.ExplosiveApi
 import net.minecraft.particle.ParticleTypes
 import net.minecraft.util.math.Vec3d
 import moe.nea.firmament.annotations.Subscribe
 import moe.nea.firmament.events.ParticleSpawnEvent
 import moe.nea.firmament.features.FirmamentFeature
 import moe.nea.firmament.gui.config.ManagedConfig
-import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.compatloader.CompatLoader
 
 object CompatibliltyFeatures : FirmamentFeature {
-    override val identifier: String
-        get() = "compatibility"
-
-    object TConfig : ManagedConfig(identifier, Category.INTEGRATIONS) {
-        val enhancedExplosions by toggle("explosion-enabled") { false }
-        val explosionSize by integer("explosion-power", 10, 50) { 1 }
-    }
-
-    override val config: ManagedConfig?
-        get() = TConfig
-
-    interface ExplosiveApiWrapper {
-        fun spawnParticle(vec3d: Vec3d, power: Float)
-    }
-
-    class ExplosiveApiWrapperImpl : ExplosiveApiWrapper {
-        override fun spawnParticle(vec3d: Vec3d, power: Float) {
-            ExplosiveApi.spawnParticles(MC.world, vec3d.x, vec3d.y, vec3d.z, TConfig.explosionSize / 10F)
-        }
-    }
-
-    val explosiveApiWrapper = if (FabricLoader.getInstance().isModLoaded("explosiveenhancement")) {
-        ExplosiveApiWrapperImpl()
-    } else null
-
-    @Subscribe
-    fun onExplosion(it: ParticleSpawnEvent) {
-        if (TConfig.enhancedExplosions &&
-            it.particleEffect.type == ParticleTypes.EXPLOSION_EMITTER &&
-            explosiveApiWrapper != null
-        ) {
-            it.cancel()
-            explosiveApiWrapper.spawnParticle(it.position, 2F)
-        }
-    }
+	override val identifier: String
+		get() = "compatibility"
+
+	object TConfig : ManagedConfig(identifier, Category.INTEGRATIONS) {
+		val enhancedExplosions by toggle("explosion-enabled") { false }
+		val explosionSize by integer("explosion-power", 10, 50) { 1 }
+	}
+
+	override val config: ManagedConfig?
+		get() = TConfig
+
+	interface ExplosiveApiWrapper {
+		fun spawnParticle(vec3d: Vec3d, power: Float)
+
+		companion object : CompatLoader<ExplosiveApiWrapper>(ExplosiveApiWrapper::class.java)
+	}
+
+	private val explosiveApiWrapper = ExplosiveApiWrapper.singleInstance
+
+	@Subscribe
+	fun onExplosion(it: ParticleSpawnEvent) {
+		if (TConfig.enhancedExplosions &&
+			it.particleEffect.type == ParticleTypes.EXPLOSION_EMITTER &&
+			explosiveApiWrapper != null
+		) {
+			it.cancel()
+			explosiveApiWrapper.spawnParticle(it.position, 2F)
+		}
+	}
 }
diff --git a/src/main/kotlin/util/compatloader/CompatLoader.kt b/src/main/kotlin/util/compatloader/CompatLoader.kt
new file mode 100644
index 0000000..c5d45bc
--- /dev/null
+++ b/src/main/kotlin/util/compatloader/CompatLoader.kt
@@ -0,0 +1,47 @@
+package moe.nea.firmament.util.compatloader
+
+import java.util.ServiceLoader
+import net.fabricmc.loader.api.FabricLoader
+import kotlin.streams.asSequence
+import moe.nea.firmament.Firmament
+
+abstract class CompatLoader<T : Any>(val kClass: Class<T>) {
+	val loader: ServiceLoader<T> = ServiceLoader.load(kClass)
+	val allValidInstances by lazy {
+		loader.reload()
+		loader.stream()
+			.asSequence()
+			.filter { provider ->
+				runCatching {
+					shouldLoad(provider.type())
+				}.getOrElse {
+					Firmament.logger.error("Could not determine whether to load a ${kClass.name} subclass", it)
+					false
+				}
+			}
+			.mapNotNull { provider ->
+				runCatching {
+					provider.get()
+				}.getOrElse {
+					Firmament.logger.error(
+						"Could not load desired instance ${provider.type().name} for ${kClass.name}",
+						it)
+					null
+				}
+			}
+			.toList()
+	}
+	val singleInstance by lazy { allValidInstances.singleOrNull() }
+
+	open fun shouldLoad(type: Class<out T>): Boolean {
+		return checkRequiredModsPresent(type)
+	}
+
+	fun checkRequiredModsPresent(type: Class<*>): Boolean {
+		val requiredMods = type.getAnnotationsByType(RequireMod::class.java)
+		return requiredMods.all { FabricLoader.getInstance().isModLoaded(it.modId) }
+	}
+
+	@Repeatable
+	annotation class RequireMod(val modId: String)
+}
-- 
cgit