diff options
19 files changed, 366 insertions, 101 deletions
diff --git a/build.gradle.kts b/build.gradle.kts index fe527ba..90eb334 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,6 +8,7 @@ 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.tasks.KotlinCompile @@ -96,7 +97,7 @@ val compatSourceSets: MutableSet<SourceSet> = mutableSetOf() fun createIsolatedSourceSet(name: String, path: String = "compat/$name"): SourceSet { val ss = sourceSets.create(name) { this.java.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java"))) - this.kotlin.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/kotlin"))) + this.kotlin.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java"))) } compatSourceSets.add(ss) loom.createRemapConfigurations(ss) @@ -111,12 +112,15 @@ fun createIsolatedSourceSet(name: String, path: String = "compat/$name"): Source (mainSS.runtimeOnlyConfigurationName) { extendsFrom(getByName(ss.runtimeClasspathConfigurationName)) } + ("ksp" + ss.name.replaceFirstChar { it.uppercaseChar() }) { + extendsFrom(ksp.get()) + } } dependencies { runtimeOnly(ss.output) (ss.implementationConfigurationName)(sourceSets.main.get().output) } - tasks.jar { + tasks.shadowJar { from(ss.output) } return ss @@ -171,6 +175,8 @@ dependencies { include(libs.hypixelmodapi.fabric) compileOnly(project(":javaplugin")) annotationProcessor(project(":javaplugin")) + implementation("com.google.auto.service:auto-service-annotations:1.1.1") + ksp("dev.zacsweers.autoservice:auto-service-ksp:1.2.0") include(libs.manninghamMills) include(libs.moulconfig) @@ -285,6 +291,7 @@ tasks.shadowJar { archiveClassifier.set("dev") relocate("io.github.moulberry.repo", "moe.nea.firmament.deps.repo") destinationDirectory.set(layout.buildDirectory.dir("badjars")) + mergeServiceFiles() } tasks.remapJar { diff --git a/src/compat/configured/java/BaseConfigNode.kt b/src/compat/configured/java/BaseConfigNode.kt new file mode 100644 index 0000000..7330990 --- /dev/null +++ b/src/compat/configured/java/BaseConfigNode.kt @@ -0,0 +1,39 @@ +package moe.nea.firmament.compat.configured + +import com.mrcrayfish.configured.api.IConfigEntry +import com.mrcrayfish.configured.api.IConfigValue +import net.minecraft.text.Text +import moe.nea.firmament.gui.config.AllConfigsGui + +object BaseConfigNode : IConfigEntry { + override fun getChildren(): List<IConfigEntry> { + return AllConfigsGui.allConfigs.map { + ConfigNode(it) + } + } + + override fun isRoot(): Boolean { + return true + } + + override fun isLeaf(): Boolean { + return false + } + + override fun getValue(): IConfigValue<*>? { + return null + } + + override fun getEntryName(): String { + return "Firmament" + } + + override fun getTooltip(): Text? { + return null + } + + override fun getTranslationKey(): String? { + return null + } + +} diff --git a/src/compat/configured/java/ConfigCategory.kt b/src/compat/configured/java/ConfigCategory.kt new file mode 100644 index 0000000..4e33b8b --- /dev/null +++ b/src/compat/configured/java/ConfigCategory.kt @@ -0,0 +1,48 @@ +package moe.nea.firmament.compat.configured + +import com.mrcrayfish.configured.api.ConfigType +import com.mrcrayfish.configured.api.IConfigEntry +import com.mrcrayfish.configured.api.IModConfig +import com.mrcrayfish.configured.util.ConfigHelper +import java.nio.file.Path +import java.util.function.Consumer +import moe.nea.firmament.Firmament +import moe.nea.firmament.gui.config.ManagedConfig + +class ConfigCategory( + val category: ManagedConfig +) : BaseConfig() { + + override fun getRoot(): IConfigEntry { + return ConfigNode(category) + } + + override fun getTranslationKey(): String? { + return category.translationKey + } +} + +abstract class BaseConfig : IModConfig { + override fun update(p0: IConfigEntry) { + ConfigHelper.getChangedValues(p0).forEach { + it as ConfigValue + it.saveValue() + } + } + + override fun getType(): ConfigType { + return ConfigType.CLIENT + } + + override fun getFileName(): String { + return "" + } + + override fun getModId(): String { + return Firmament.MOD_ID + } + + override fun loadWorldConfig(p0: Path?, p1: Consumer<IModConfig>?) { + } + +} diff --git a/src/compat/configured/java/ConfigNode.kt b/src/compat/configured/java/ConfigNode.kt new file mode 100644 index 0000000..16e54a6 --- /dev/null +++ b/src/compat/configured/java/ConfigNode.kt @@ -0,0 +1,39 @@ +package moe.nea.firmament.compat.configured + +import com.mrcrayfish.configured.api.IConfigEntry +import com.mrcrayfish.configured.api.IConfigValue +import net.minecraft.text.Text +import moe.nea.firmament.gui.config.ManagedConfig + +class ConfigNode(val config: ManagedConfig) : IConfigEntry { + override fun getChildren(): List<IConfigEntry> { + return config.allOptions.map { + ConfigValueNode(it.value) + } + } + + override fun isRoot(): Boolean { + return false + } + + override fun isLeaf(): Boolean { + return false + } + + override fun getValue(): IConfigValue<*>? { + return null + } + + override fun getEntryName(): String { + return config.translationKey + } + + override fun getTooltip(): Text? { + return null + } + + override fun getTranslationKey(): String { + return config.translationKey + } + +} diff --git a/src/compat/configured/java/ConfigValue.kt b/src/compat/configured/java/ConfigValue.kt new file mode 100644 index 0000000..e16c51c --- /dev/null +++ b/src/compat/configured/java/ConfigValue.kt @@ -0,0 +1,72 @@ +package moe.nea.firmament.compat.configured + +import com.mrcrayfish.configured.api.IConfigValue +import net.minecraft.text.Text +import moe.nea.firmament.gui.config.ManagedOption + +class ConfigValue<T: Any>(val option: ManagedOption<T>) : IConfigValue<T> { + var value = option.get() + var initialValue = option.get() + + override fun get(): T { + return value + } + + override fun set(p0: T) { + this.value = p0 + } + + override fun getDefault(): T { + return option.default() + } + + override fun isDefault(): Boolean { + // TODO: should this be an option in handlers? + return option == option.default() + } + + override fun isChanged(): Boolean { + return value != initialValue + } + + override fun restore() { + this.value = option.default() + } + + override fun getComment(): Text? { + return null + } + + override fun getTranslationKey(): String? { + return option.rawLabelText + } + + override fun getValidationHint(): Text? { + return null + } + + override fun getName(): String { + return "" + } + + override fun cleanCache() { + + } + + override fun requiresWorldRestart(): Boolean { + return false + } + + override fun requiresGameRestart(): Boolean { + return false + } + + override fun isValid(p0: T): Boolean { + // TODO: should this be validated? + return true + } + + fun saveValue() { + option.set(value) + } +} diff --git a/src/compat/configured/java/ConfigValueNode.kt b/src/compat/configured/java/ConfigValueNode.kt new file mode 100644 index 0000000..df59739 --- /dev/null +++ b/src/compat/configured/java/ConfigValueNode.kt @@ -0,0 +1,37 @@ +package moe.nea.firmament.compat.configured + +import com.mrcrayfish.configured.api.IConfigEntry +import com.mrcrayfish.configured.api.IConfigValue +import net.minecraft.text.Text +import moe.nea.firmament.gui.config.ManagedOption + +class ConfigValueNode(val option: ManagedOption<*>) : IConfigEntry { + override fun getChildren(): List<IConfigEntry> { + return listOf() + } + + override fun isRoot(): Boolean { + return false + } + + override fun isLeaf(): Boolean { + return true + } + + val value = ConfigValue(option) + override fun getValue(): IConfigValue<*>? { + return value + } + + override fun getEntryName(): String { + return option.propertyName + } + + override fun getTooltip(): Text? { + return null + } + + override fun getTranslationKey(): String? { + return option.rawLabelText + } +} diff --git a/src/compat/configured/java/ConfiguredCompat.kt b/src/compat/configured/java/ConfiguredCompat.kt new file mode 100644 index 0000000..a5b78bb --- /dev/null +++ b/src/compat/configured/java/ConfiguredCompat.kt @@ -0,0 +1,29 @@ +package moe.nea.firmament.compat.configured + +import com.mrcrayfish.configured.api.IConfigEntry +import com.mrcrayfish.configured.api.IModConfig +import com.mrcrayfish.configured.api.IModConfigProvider +import com.mrcrayfish.configured.api.ModContext +import moe.nea.firmament.Firmament +import moe.nea.firmament.gui.config.AllConfigsGui + +/** + * Registered in `fabric.mod.json` at `custom.configured.providers` + */ +class ConfiguredCompat : IModConfigProvider { + override fun getConfigurationsForMod(modContext: ModContext): Set<IModConfig> { + if (modContext.modId != Firmament.MOD_ID) return emptySet() + return buildSet { + add(object : BaseConfig() { + override fun getRoot(): IConfigEntry { + return BaseConfigNode + } + + override fun getTranslationKey(): String? { + return "firmament.config.all-configs" + } + }) + AllConfigsGui.allConfigs.mapTo(this) { ConfigCategory(it) } + } + } +} diff --git a/src/compat/configured/java/ConfiguredConfigScreenProvider.kt b/src/compat/configured/java/ConfiguredConfigScreenProvider.kt new file mode 100644 index 0000000..c0095bf --- /dev/null +++ b/src/compat/configured/java/ConfiguredConfigScreenProvider.kt @@ -0,0 +1,22 @@ +package moe.nea.firmament.compat.configured + +import com.google.auto.service.AutoService +import com.mrcrayfish.configured.integration.CatalogueConfigFactory +import net.fabricmc.loader.api.FabricLoader +import net.minecraft.client.gui.screen.Screen +import moe.nea.firmament.Firmament +import moe.nea.firmament.gui.config.FirmamentConfigScreenProvider + +@AutoService(FirmamentConfigScreenProvider::class) +class ConfiguredConfigScreenProvider : FirmamentConfigScreenProvider { + override val key: String + get() = "configured" + override val isEnabled: Boolean + get() = FabricLoader.getInstance().isModLoaded("configured") + + override fun open(parent: Screen?): Screen { + return CatalogueConfigFactory.createConfigScreen( + parent, + FabricLoader.getInstance().getModContainer(Firmament.MOD_ID).get()) + } +} diff --git a/src/compat/sodium/java/SodiumChunkReloader.kt b/src/compat/sodium/java/SodiumChunkReloader.kt index 9456861..932c338 100644 --- a/src/compat/sodium/java/SodiumChunkReloader.kt +++ b/src/compat/sodium/java/SodiumChunkReloader.kt @@ -1,3 +1,5 @@ +package moe.nea.firmament.compat.sodium + import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer import moe.nea.firmament.mixins.accessor.sodium.AccessorSodiumWorldRenderer diff --git a/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java b/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java index e3644c0..9b891a4 100644 --- a/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java +++ b/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java @@ -146,7 +146,9 @@ public class AutoDiscoveryPlugin { */ private void walkDir(Path classRoot) { System.out.println("Trying to find mixins from directory"); - try (Stream<Path> classes = Files.walk(classRoot.resolve(getMixinBaseDir()))) { + var path = classRoot.resolve(getMixinBaseDir()); + if (!Files.exists(path)) return; + try (Stream<Path> classes = Files.walk(path)) { classes.map(it -> classRoot.relativize(it).toString()) .forEach(this::tryAddMixinClass); } catch (IOException e) { diff --git a/src/main/kotlin/gui/config/AllConfigsGui.kt b/src/main/kotlin/gui/config/AllConfigsGui.kt index 4f7731c..3091b2a 100644 --- a/src/main/kotlin/gui/config/AllConfigsGui.kt +++ b/src/main/kotlin/gui/config/AllConfigsGui.kt @@ -1,5 +1,3 @@ - - package moe.nea.firmament.gui.config import io.github.notenoughupdates.moulconfig.observer.ObservableList @@ -36,10 +34,16 @@ object AllConfigsGui { } } - fun makeScreen(parent: Screen? = null): Screen { + fun makeBuiltInScreen(parent: Screen? = null): Screen { return MoulConfigUtils.loadScreen("config/main", MainMapping(allConfigs), parent) } + fun makeScreen(parent: Screen? = null): Screen { + val provider = FirmamentConfigScreenProvider.providers.find { it.key == "builtin" } + ?: FirmamentConfigScreenProvider.providers.first() + return provider.open(parent) + } + fun showAllGuis() { setScreenLater(makeScreen()) } diff --git a/src/main/kotlin/gui/config/BuiltInConfigScreenProvider.kt b/src/main/kotlin/gui/config/BuiltInConfigScreenProvider.kt new file mode 100644 index 0000000..19e7383 --- /dev/null +++ b/src/main/kotlin/gui/config/BuiltInConfigScreenProvider.kt @@ -0,0 +1,14 @@ +package moe.nea.firmament.gui.config + +import com.google.auto.service.AutoService +import net.minecraft.client.gui.screen.Screen + +@AutoService(FirmamentConfigScreenProvider::class) +class BuiltInConfigScreenProvider : FirmamentConfigScreenProvider { + override val key: String + get() = "builtin" + + override fun open(parent: Screen?): Screen { + return AllConfigsGui.makeBuiltInScreen(parent) + } +} diff --git a/src/main/kotlin/gui/config/FirmamentConfigScreenProvider.kt b/src/main/kotlin/gui/config/FirmamentConfigScreenProvider.kt new file mode 100644 index 0000000..582f701 --- /dev/null +++ b/src/main/kotlin/gui/config/FirmamentConfigScreenProvider.kt @@ -0,0 +1,27 @@ +package moe.nea.firmament.gui.config + +import java.util.ServiceLoader +import kotlin.streams.asSequence +import net.minecraft.client.gui.screen.Screen +import moe.nea.firmament.Firmament + +interface FirmamentConfigScreenProvider { + val key: String + val isEnabled: Boolean get() = true + + fun open(parent: Screen?): Screen + + companion object { + private val loader = ServiceLoader.load(FirmamentConfigScreenProvider::class.java) + + val providers by lazy { + loader.stream().asSequence().mapNotNull { service -> + kotlin.runCatching { service.get() } + .getOrElse { + Firmament.logger.warn("Could not load config provider ${service.type()}", it) + null + } + }.filter { it.isEnabled }.toList() + } + } +} diff --git a/src/main/kotlin/gui/config/ManagedConfig.kt b/src/main/kotlin/gui/config/ManagedConfig.kt index aa6e3c8..0d942e2 100644 --- a/src/main/kotlin/gui/config/ManagedConfig.kt +++ b/src/main/kotlin/gui/config/ManagedConfig.kt @@ -145,7 +145,8 @@ abstract class ManagedConfig(override val name: String) : ManagedConfigElement() latestGuiAppender?.reloadables?.forEach { it() } } - val labelText = Text.translatable("firmament.config.${name}") + val translationKey get() = "firmament.config.${name}" + val labelText = Text.translatable(translationKey) fun getConfigEditor(parent: Screen? = null): Screen { var screen: Screen? = null diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json index dd514fe..2e516df 100644 --- a/src/main/resources/assets/firmament/lang/en_us.json +++ b/src/main/resources/assets/firmament/lang/en_us.json @@ -20,6 +20,7 @@ "firmament.poweruser.entity.armor": "Entity Armor:", "firmament.poweruser.entity.armor.item": " - %s", "firmament.poweruser.entity.passengers": "%s Passengers", + "firmament.config.all-configs": "- All Configs -", "firmament.config.anniversary": "Anniversary Features", "firmament.config.anniversary.shiny-pigs": "Shiny Pigs Tracker", "firmament.config.anniversary.pig-hud": "Pig Tracker Hud", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index ef2920e..e027783 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -50,6 +50,11 @@ "roughlyenoughitems": ">=${rei_version}" }, "custom": { + "configured": { + "providers": [ + "moe.nea.firmament.compat.configured.ConfiguredCompat" + ] + }, "modmenu": { "links": { "modmenu.discord": "https://discord.gg/64pFP94AWA" diff --git a/src/main/resources/firmament.mixins.json b/src/main/resources/firmament.mixins.json new file mode 100644 index 0000000..dbb8290 --- /dev/null +++ b/src/main/resources/firmament.mixins.json @@ -0,0 +1,7 @@ +{ + "required": true, + "plugin": "moe.nea.firmament.init.MixinPlugin", + "package": "moe.nea.firmament.mixins", + "compatibilityLevel": "JAVA_21", + "refmap": "Firmament-refmap.json" +} diff --git a/src/main/resources/firmament.mixins.json.license b/src/main/resources/firmament.mixins.json.license new file mode 100644 index 0000000..5f0659f --- /dev/null +++ b/src/main/resources/firmament.mixins.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + +SPDX-License-Identifier: CC0-1.0 diff --git a/symbols/src/main/kotlin/process/MixinAnnotationProcessor.kt b/symbols/src/main/kotlin/process/MixinAnnotationProcessor.kt deleted file mode 100644 index 4e2c93f..0000000 --- a/symbols/src/main/kotlin/process/MixinAnnotationProcessor.kt +++ /dev/null @@ -1,94 +0,0 @@ - -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.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.Origin -import com.google.gson.Gson -import com.google.gson.JsonArray -import com.google.gson.JsonObject - - -class MixinAnnotationProcessor( - val codeGenerator: CodeGenerator, - val logger: KSPLogger -) : SymbolProcessor { - @AutoService(SymbolProcessorProvider::class) - class Provider : SymbolProcessorProvider { - override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { - return MixinAnnotationProcessor(environment.codeGenerator, environment.logger) - } - } - - val mixinPackage = "moe.nea.firmament.mixins" - val refmapName = "Firmament-refmap.json" - val mixinPlugin = "moe.nea.firmament.init.MixinPlugin" - val scaffold = """ -{ - "required": true, - "plugin": "moe.nea.firmament.init.MixinPlugin", - "package": "{mixinPackage}", - "compatibilityLevel": "JAVA_17", - "injectors": { - "defaultRequire": 1 - }, - "refmap": "{refmapName}", - "client": {mixins} -} -""" - var rounds = mutableListOf<KSClassDeclaration>() - - override fun process(resolver: Resolver): List<KSAnnotated> { - return resolver.getSymbolsWithAnnotation("org.spongepowered.asm.mixin.Mixin") - .filter { !processElement(it, resolver) }.toList() - } - - override fun finish() { - val output = codeGenerator.createNewFile( - Dependencies( - aggregating = true, - *rounds.map { it.containingFile!! }.toTypedArray()), - "", "firmament.mixins", - extensionName = "json") - val writer = output.writer() - val gson = Gson() - val mixinJson = JsonObject() - mixinJson.addProperty("required", true) - mixinJson.addProperty("plugin", mixinPlugin) - mixinJson.addProperty("package", mixinPackage) - mixinJson.addProperty("compatibilityLevel", "JAVA_21") - mixinJson.addProperty("refmap", refmapName) - val mixinArray = JsonArray() - rounds.map { it.qualifiedName!!.asString().removePrefix("$mixinPackage.") } - .sorted() - .forEach(mixinArray::add) - mixinJson.add("client", mixinArray) - gson.toJson(mixinJson, writer) - writer.close() - rounds - } - - private fun processElement(decl: KSAnnotated, resolver: Resolver): Boolean { - if (decl !is KSClassDeclaration) { - logger.error("@Mixin only allowed on class declarations", decl) - return true - } - decl.qualifiedName ?: logger.error("@Mixin only allowed on classes with a proper name") - if (decl.origin != Origin.JAVA) logger.error("@Mixin only allowed in java code") - val packageName = decl.packageName.asString() - if (packageName != mixinPackage && !packageName.startsWith("$mixinPackage.")) - logger.error("@Mixin outside of mixin package", decl) - rounds.add(decl) - return true - } - - -} |