diff options
Diffstat (limited to 'src/main')
78 files changed, 996 insertions, 308 deletions
diff --git a/src/main/java/moe/nea/firmament/gui/config/storage/ArrayIndexedJsonPointer.kt b/src/main/java/moe/nea/firmament/gui/config/storage/ArrayIndexedJsonPointer.kt new file mode 100644 index 0000000..1e204d6 --- /dev/null +++ b/src/main/java/moe/nea/firmament/gui/config/storage/ArrayIndexedJsonPointer.kt @@ -0,0 +1,17 @@ +package moe.nea.firmament.gui.config.storage + +import com.google.gson.JsonArray +import com.google.gson.JsonElement + +data class ArrayIndexedJsonPointer( + val owner: JsonArray, + val index: Int +) : JsonPointer { + override fun get(): JsonElement { + return owner.get(index) + } + + override fun set(value: JsonElement) { + owner.set(index, value) + } +} diff --git a/src/main/java/moe/nea/firmament/gui/config/storage/ConfigEditor.kt b/src/main/java/moe/nea/firmament/gui/config/storage/ConfigEditor.kt new file mode 100644 index 0000000..df1ed33 --- /dev/null +++ b/src/main/java/moe/nea/firmament/gui/config/storage/ConfigEditor.kt @@ -0,0 +1,104 @@ +package moe.nea.firmament.gui.config.storage + +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import kotlinx.serialization.json.JsonElement +import moe.nea.firmament.util.json.intoGson +import moe.nea.firmament.util.json.intoKotlinJson + +data class ConfigEditor( + val roots: List<JsonPointer>, +) { + fun transform(transform: (JsonElement) -> JsonElement) { + roots.forEach { root -> + root.set(transform(root.get().intoKotlinJson()).intoGson()) + } + } + + fun move(fromPath: String, toPath: String) { + if (fromPath == toPath) return + val fromSegments = fromPath.split(".").filter { it.isNotEmpty() } + val toSegments = toPath.split(".").filter { it.isNotEmpty() } + roots.forEach { root -> + var fp = root.get() + if (fromSegments.isEmpty()) { + root.set(JsonObject()) + } else { + fromSegments.dropLast(1).forEach { + fp = (fp as JsonObject)[it] ?: return@forEach // todo warn if we dont find the object maybe + } + fp as JsonObject + fp = fp.remove(fromSegments.last())?.deepCopy() ?: return@forEach // in theory i don't need to deepcopy but fuck theory + } + if (toSegments.isEmpty()) { + root.set(fp) + } else { + var lp = root.get() + toSegments.dropLast(1).forEach { name -> + val parent = lp as JsonObject + var child = parent[name] + if (child == null) { + child = JsonObject() + parent.add(name, child) + } + lp = child + } + lp as JsonObject + if (lp.has(toSegments.last())) { + error("Cannot overwrite $lp.${toSegments.last()} with $fp") + } + lp.add(toSegments.last(), fp) + } + } + } + + fun at(path: String, block: ConfigEditor.() -> Unit) { + block(at(path)) + } + + fun at(path: String): ConfigEditor { + var lastRoots = roots + for (segment in path.split(".")) { + if (segment.isEmpty()) { + continue + } else if (segment == "*") { + lastRoots = lastRoots.flatMap { root -> + when (val ele = root.get()) { + is JsonObject -> { + ele.entrySet().map { + (ObjectIndexedJsonPointer(ele, it.key)) + } + } + + is JsonArray -> { + (0..<ele.size()).map { + (ArrayIndexedJsonPointer(ele, it)) + } + } + + else -> { + error("Cannot expand a json primitive $ele at $path") + } + } + } + } else { + lastRoots = lastRoots.map { root -> + when (val ele = root.get()) { + is JsonObject -> { + ObjectIndexedJsonPointer(ele, segment) + } + + is JsonArray -> { + ArrayIndexedJsonPointer(ele, segment.toInt()) + } + + else -> { + error("Cannot expand a json primitive $ele at $path") + } + } + } + } + } + return ConfigEditor(lastRoots) + } +} diff --git a/src/main/java/moe/nea/firmament/gui/config/storage/ConfigFixEvent.kt b/src/main/java/moe/nea/firmament/gui/config/storage/ConfigFixEvent.kt new file mode 100644 index 0000000..07148d5 --- /dev/null +++ b/src/main/java/moe/nea/firmament/gui/config/storage/ConfigFixEvent.kt @@ -0,0 +1,38 @@ +package moe.nea.firmament.gui.config.storage + +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import moe.nea.firmament.events.FirmamentEvent +import moe.nea.firmament.events.FirmamentEventBus + +data class ConfigFixEvent( + val storageClass: ConfigStorageClass, + val toVersion: Int, + var data: JsonObject, +) : FirmamentEvent() { + companion object : FirmamentEventBus<ConfigFixEvent>() { + + } + fun on( + toVersion: Int, + storageClass: ConfigStorageClass, + block: ConfigEditor.() -> Unit + ) { + require(toVersion <= FirmamentConfigLoader.currentConfigVersion) + if (this.toVersion == toVersion && this.storageClass == storageClass) { + block(ConfigEditor(listOf(object : JsonPointer { + override fun get(): JsonObject { + return data + } + + override fun set(value: JsonElement) { + data = value as JsonObject + } + + override fun toString(): String { + return "ConfigRoot($storageClass)" + } + }))) + } + } +} diff --git a/src/main/java/moe/nea/firmament/gui/config/storage/JsonPointer.kt b/src/main/java/moe/nea/firmament/gui/config/storage/JsonPointer.kt new file mode 100644 index 0000000..e34c312 --- /dev/null +++ b/src/main/java/moe/nea/firmament/gui/config/storage/JsonPointer.kt @@ -0,0 +1,8 @@ +package moe.nea.firmament.gui.config.storage + +import com.google.gson.JsonElement + +interface JsonPointer { + fun get(): JsonElement + fun set(value: JsonElement) +} diff --git a/src/main/java/moe/nea/firmament/gui/config/storage/ObjectIndexedJsonPointer.kt b/src/main/java/moe/nea/firmament/gui/config/storage/ObjectIndexedJsonPointer.kt new file mode 100644 index 0000000..091275d --- /dev/null +++ b/src/main/java/moe/nea/firmament/gui/config/storage/ObjectIndexedJsonPointer.kt @@ -0,0 +1,17 @@ +package moe.nea.firmament.gui.config.storage + +import com.google.gson.JsonElement +import com.google.gson.JsonObject + +data class ObjectIndexedJsonPointer( + val owner: JsonObject, + val name: String +) : JsonPointer { + override fun get(): JsonElement { + return owner.get(name) + } + + override fun set(value: JsonElement) { + owner.add(name, value) + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/FirmKeybindsInVanillaControlsPatch.java b/src/main/java/moe/nea/firmament/mixins/FirmKeybindsInVanillaControlsPatch.java index 699d5b7..4c9f925 100644 --- a/src/main/java/moe/nea/firmament/mixins/FirmKeybindsInVanillaControlsPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/FirmKeybindsInVanillaControlsPatch.java @@ -3,7 +3,6 @@ package moe.nea.firmament.mixins; import moe.nea.firmament.gui.config.KeyBindingHandler; -import moe.nea.firmament.gui.config.ManagedConfig; import moe.nea.firmament.keybindings.FirmamentKeyBindings; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.option.ControlsListWidget; diff --git a/src/main/kotlin/gui/config/ManagedConfig.kt b/src/main/java/moe/nea/firmament/util/data/ManagedConfig.kt index 90e58d0..169dad1 100644 --- a/src/main/kotlin/gui/config/ManagedConfig.kt +++ b/src/main/java/moe/nea/firmament/util/data/ManagedConfig.kt @@ -1,4 +1,4 @@ -package moe.nea.firmament.gui.config +package moe.nea.firmament.util.data import com.mojang.serialization.Codec import io.github.notenoughupdates.moulconfig.ChromaColour @@ -11,32 +11,42 @@ import io.github.notenoughupdates.moulconfig.gui.component.RowComponent import io.github.notenoughupdates.moulconfig.gui.component.ScrollPanelComponent import io.github.notenoughupdates.moulconfig.gui.component.TextComponent import io.github.notenoughupdates.moulconfig.platform.MoulConfigScreenComponent -import moe.nea.jarvis.api.Point -import org.joml.Vector2i -import org.lwjgl.glfw.GLFW -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject -import kotlin.io.path.createDirectories -import kotlin.io.path.readText -import kotlin.io.path.writeText -import kotlin.time.Duration -import net.minecraft.client.gui.screen.Screen -import net.minecraft.text.Text -import net.minecraft.util.StringIdentifiable import moe.nea.firmament.Firmament import moe.nea.firmament.gui.FirmButtonComponent -import moe.nea.firmament.keybindings.GenericInputButton -import moe.nea.firmament.keybindings.InputModifiers +import moe.nea.firmament.gui.config.AllConfigsGui +import moe.nea.firmament.gui.config.BooleanHandler +import moe.nea.firmament.gui.config.ChoiceHandler +import moe.nea.firmament.gui.config.ClickHandler +import moe.nea.firmament.gui.config.ColourHandler +import moe.nea.firmament.gui.config.DurationHandler +import moe.nea.firmament.gui.config.GuiAppender +import moe.nea.firmament.gui.config.HudMeta +import moe.nea.firmament.gui.config.HudMetaHandler +import moe.nea.firmament.gui.config.HudPosition +import moe.nea.firmament.gui.config.IntegerHandler +import moe.nea.firmament.gui.config.KeyBindingHandler +import moe.nea.firmament.gui.config.ManagedOption +import moe.nea.firmament.gui.config.StringHandler import moe.nea.firmament.keybindings.SavedKeyBinding -import moe.nea.firmament.util.ScreenUtil.setScreenLater +import moe.nea.firmament.util.ScreenUtil import moe.nea.firmament.util.collections.InstanceList +import net.minecraft.client.gui.screen.Screen +import net.minecraft.text.Text +import net.minecraft.util.StringIdentifiable +import org.joml.Vector2i +import kotlinx.serialization.json.buildJsonObject +import kotlin.io.path.createDirectories +import kotlin.io.path.readText +import kotlin.io.path.writeText +import kotlin.time.Duration +import moe.nea.firmament.gui.config.storage.ConfigStorageClass abstract class ManagedConfig( - override val name: String, + val name: String, val category: Category, - // TODO: allow vararg secondaryCategories: Category, -) : ManagedConfigElement() { +) : IDataHolder<Unit> { enum class Category { // Böse Kategorie, nicht benutzten lol MISC, @@ -75,29 +85,32 @@ abstract class ManagedConfig( category.configs.add(this) } - // TODO: warn if two files use the same config file name :( - val file = Firmament.CONFIG_DIR.resolve("$name.json") - val data: JsonObject by lazy { - try { - Firmament.json.decodeFromString( - file.readText() - ) - } catch (e: Exception) { - Firmament.logger.info("Could not read config $name. Loading empty config.") - JsonObject(mutableMapOf()) + override fun keys(): Collection<Unit> { + return listOf(Unit) + } + + override fun clear() { + sortedOptions.forEach { + it._actualValue = null } } - fun save() { - val data = JsonObject(allOptions.mapNotNull { (key, value) -> - value.toJson()?.let { - key to it + override val storageClass: ConfigStorageClass + get() = ConfigStorageClass.CONFIG + + override fun saveTo(key: Unit): JsonObject { + return buildJsonObject { + sortedOptions.forEach { + put(it.propertyName, it.toJson() ?: return@forEach) } - }.toMap()) - file.parent.createDirectories() - file.writeText(Firmament.json.encodeToString(data)) + } } + override fun loadFrom(key: Unit, jsonObject: JsonObject) { + sortedOptions.forEach { + it.load(jsonObject) + } + } val allOptions = mutableMapOf<String, ManagedOption<*>>() val sortedOptions = mutableListOf<ManagedOption<*>>() @@ -112,7 +125,6 @@ abstract class ManagedConfig( if (propertyName in allOptions) error("Cannot register the same name twice") return ManagedOption(this, propertyName, default, handler).also { it.handler.initOption(it) - it.load(data) allOptions[propertyName] = it sortedOptions.add(it) } @@ -188,7 +200,7 @@ abstract class ManagedConfig( propertyName: String, default: () -> Int, ): ManagedOption<SavedKeyBinding> = keyBindingWithOutDefaultModifiers(propertyName) { - SavedKeyBinding.keyWithoutMods(default()) + SavedKeyBinding.Companion.keyWithoutMods(default()) } protected fun keyBindingWithOutDefaultModifiers( @@ -201,7 +213,7 @@ abstract class ManagedConfig( protected fun keyBindingWithDefaultUnbound( propertyName: String, ): ManagedOption<SavedKeyBinding> { - return keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding.unbound() } + return keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding.Companion.unbound() } } protected fun integer( @@ -237,8 +249,8 @@ abstract class ManagedConfig( RowComponent( FirmButtonComponent(TextComponent("←")) { if (parent != null) { - save() - setScreenLater(parent) + markDirty() + ScreenUtil.setScreenLater(parent) } else { AllConfigsGui.showAllGuis() } @@ -264,7 +276,7 @@ abstract class ManagedConfig( } fun showConfigEditor(parent: Screen? = null) { - setScreenLater(getConfigEditor(parent)) + ScreenUtil.setScreenLater(getConfigEditor(parent)) } } diff --git a/src/main/kotlin/Firmament.kt b/src/main/kotlin/Firmament.kt index 83cc259..198defa 100644 --- a/src/main/kotlin/Firmament.kt +++ b/src/main/kotlin/Firmament.kt @@ -46,6 +46,7 @@ import moe.nea.firmament.events.ScreenRenderPostEvent import moe.nea.firmament.events.TickEvent import moe.nea.firmament.events.registration.registerFirmamentEvents import moe.nea.firmament.features.FeatureManager +import moe.nea.firmament.gui.config.storage.FirmamentConfigLoader import moe.nea.firmament.repo.HypixelStaticData import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.util.MC @@ -137,10 +138,10 @@ object Firmament { fun onClientInitialize() { InitLevel.bump(InitLevel.MC_INIT) FeatureManager.subscribeEvents() + FirmamentConfigLoader.loadConfig() ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance -> TickEvent.publish(TickEvent(MC.currentTick++)) }) - IDataHolder.registerEvents() RepoManager.initialize() SBData.init() FeatureManager.autoload() diff --git a/src/main/kotlin/commands/rome.kt b/src/main/kotlin/commands/rome.kt index f808231..d12da44 100644 --- a/src/main/kotlin/commands/rome.kt +++ b/src/main/kotlin/commands/rome.kt @@ -20,7 +20,7 @@ import moe.nea.firmament.features.inventory.storageoverlay.StorageOverviewScreen import moe.nea.firmament.features.mining.MiningBlockInfoUi import moe.nea.firmament.gui.config.AllConfigsGui import moe.nea.firmament.gui.config.BooleanHandler -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.gui.config.ManagedOption import moe.nea.firmament.init.MixinPlugin import moe.nea.firmament.repo.HypixelStaticData @@ -90,7 +90,7 @@ fun firmamentCommand() = literal("firmament") { } propertyObj as ManagedOption<Boolean> propertyObj.value = !propertyObj.value - configObj.save() + configObj.markDirty() source.sendFeedback( Text.stringifiedTranslatable( "firmament.command.toggle.toggled", configObj.labelText, diff --git a/src/main/kotlin/features/FeatureManager.kt b/src/main/kotlin/features/FeatureManager.kt index 183365b..3e235f5 100644 --- a/src/main/kotlin/features/FeatureManager.kt +++ b/src/main/kotlin/features/FeatureManager.kt @@ -35,6 +35,7 @@ import moe.nea.firmament.features.misc.CustomCapes import moe.nea.firmament.features.misc.Hud import moe.nea.firmament.features.world.FairySouls import moe.nea.firmament.features.world.Waypoints +import moe.nea.firmament.util.ErrorUtil import moe.nea.firmament.util.compatloader.ICompatMeta import moe.nea.firmament.util.data.DataHolder @@ -91,16 +92,13 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature fun subscribeEvents() { SubscriptionList.allLists.forEach { list -> if (ICompatMeta.shouldLoad(list.javaClass.name)) - runCatching { + ErrorUtil.catch("Error while loading events from $list") { list.provideSubscriptions { it.owner.javaClass.classes.forEach { runCatching { it.getDeclaredField("INSTANCE").get(null) } } subscribeSingleEvent(it) } - }.getOrElse { - // TODO: allow annotating source sets to specifically opt out of loading for mods, maybe automatically - Firmament.logger.info("Ignoring events from $list, likely due to a missing compat mod.", it) } } } diff --git a/src/main/kotlin/features/FirmamentFeature.kt b/src/main/kotlin/features/FirmamentFeature.kt index 2cfc4fd..08e7019 100644 --- a/src/main/kotlin/features/FirmamentFeature.kt +++ b/src/main/kotlin/features/FirmamentFeature.kt @@ -3,7 +3,7 @@ package moe.nea.firmament.features import moe.nea.firmament.events.subscription.SubscriptionOwner -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig // TODO: remove this entire feature system and revamp config interface FirmamentFeature : SubscriptionOwner { diff --git a/src/main/kotlin/features/chat/AutoCompletions.kt b/src/main/kotlin/features/chat/AutoCompletions.kt index 9e0de40..dac1daa 100644 --- a/src/main/kotlin/features/chat/AutoCompletions.kt +++ b/src/main/kotlin/features/chat/AutoCompletions.kt @@ -9,12 +9,14 @@ import moe.nea.firmament.commands.thenExecute import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.events.MaskCommands import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.util.MC +import moe.nea.firmament.util.data.Config object AutoCompletions : FirmamentFeature { + @Config object TConfig : ManagedConfig(identifier, Category.CHAT) { val provideWarpTabCompletion by toggle("warp-complete") { true } val replaceWarpIsByWarpIsland by toggle("warp-is") { true } diff --git a/src/main/kotlin/features/chat/ChatLinks.kt b/src/main/kotlin/features/chat/ChatLinks.kt index 28c526f..6ea07d6 100644 --- a/src/main/kotlin/features/chat/ChatLinks.kt +++ b/src/main/kotlin/features/chat/ChatLinks.kt @@ -27,9 +27,10 @@ import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ModifyChatEvent import moe.nea.firmament.events.ScreenRenderPostEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.jarvis.JarvisIntegration import moe.nea.firmament.util.MC +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.render.drawTexture import moe.nea.firmament.util.transformEachRecursively import moe.nea.firmament.util.unformattedString @@ -38,6 +39,7 @@ object ChatLinks : FirmamentFeature { override val identifier: String get() = "chat-links" + @Config object TConfig : ManagedConfig(identifier, Category.CHAT) { val enableLinks by toggle("links-enabled") { true } val imageEnabled by toggle("image-enabled") { true } diff --git a/src/main/kotlin/features/chat/CopyChat.kt b/src/main/kotlin/features/chat/CopyChat.kt index 64f8734..5cd847a 100644 --- a/src/main/kotlin/features/chat/CopyChat.kt +++ b/src/main/kotlin/features/chat/CopyChat.kt @@ -4,7 +4,8 @@ import net.minecraft.text.OrderedText import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ClientStartedEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.Config +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.reconstitute @@ -12,6 +13,7 @@ object CopyChat : FirmamentFeature { override val identifier: String get() = "copy-chat" + @Config object TConfig : ManagedConfig(identifier, Category.CHAT) { val copyChat by toggle("copy-chat") { false } } diff --git a/src/main/kotlin/features/chat/PartyCommands.kt b/src/main/kotlin/features/chat/PartyCommands.kt index de3a0d9..5a80013 100644 --- a/src/main/kotlin/features/chat/PartyCommands.kt +++ b/src/main/kotlin/features/chat/PartyCommands.kt @@ -12,10 +12,11 @@ import moe.nea.firmament.commands.thenExecute import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.events.PartyMessageReceivedEvent import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.ErrorUtil import moe.nea.firmament.util.MC import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.tr import moe.nea.firmament.util.useMatch @@ -89,6 +90,7 @@ object PartyCommands { // TODO: at TPS command } + @Config object TConfig : ManagedConfig("party-commands", Category.CHAT) { val enable by toggle("enable") { false } val cooldown by duration("cooldown", 0.seconds, 20.seconds) { 2.seconds } diff --git a/src/main/kotlin/features/chat/QuickCommands.kt b/src/main/kotlin/features/chat/QuickCommands.kt index 7963171..88218b4 100644 --- a/src/main/kotlin/features/chat/QuickCommands.kt +++ b/src/main/kotlin/features/chat/QuickCommands.kt @@ -16,7 +16,7 @@ import moe.nea.firmament.commands.thenArgument import moe.nea.firmament.commands.thenExecute import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.gui.config.ManagedOption import moe.nea.firmament.util.MC import moe.nea.firmament.util.SBData diff --git a/src/main/kotlin/features/debug/DeveloperFeatures.kt b/src/main/kotlin/features/debug/DeveloperFeatures.kt index fd236f9..cb9cf00 100644 --- a/src/main/kotlin/features/debug/DeveloperFeatures.kt +++ b/src/main/kotlin/features/debug/DeveloperFeatures.kt @@ -17,11 +17,12 @@ import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.DebugInstantiateEvent import moe.nea.firmament.events.TickEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.init.MixinPlugin import moe.nea.firmament.util.MC import moe.nea.firmament.util.TimeMark import moe.nea.firmament.util.asm.AsmAnnotationUtil +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.iterate object DeveloperFeatures : FirmamentFeature { @@ -38,6 +39,7 @@ object DeveloperFeatures : FirmamentFeature { .iterate { it.parent } .find { it.resolve("settings.gradle.kts").exists() } + @Config object TConfig : ManagedConfig("developer", Category.DEV) { val autoRebuildResources by toggle("auto-rebuild") { false } } diff --git a/src/main/kotlin/features/debug/PowerUserTools.kt b/src/main/kotlin/features/debug/PowerUserTools.kt index 0800a4f..90b73bb 100644 --- a/src/main/kotlin/features/debug/PowerUserTools.kt +++ b/src/main/kotlin/features/debug/PowerUserTools.kt @@ -28,10 +28,11 @@ import moe.nea.firmament.events.ScreenChangeEvent import moe.nea.firmament.events.TickEvent import moe.nea.firmament.events.WorldKeyboardEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.mixins.accessor.AccessorHandledScreen import moe.nea.firmament.util.ClipboardUtils import moe.nea.firmament.util.MC +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.focusedItemStack import moe.nea.firmament.util.mc.IntrospectableItemModelManager import moe.nea.firmament.util.mc.SNbtFormatter @@ -47,6 +48,7 @@ object PowerUserTools : FirmamentFeature { override val identifier: String get() = "power-user" + @Config object TConfig : ManagedConfig(identifier, Category.DEV) { val showItemIds by toggle("show-item-id") { false } val copyItemId by keyBindingWithDefaultUnbound("copy-item-id") diff --git a/src/main/kotlin/features/diana/DianaWaypoints.kt b/src/main/kotlin/features/diana/DianaWaypoints.kt index 6d87262..68ee1ea 100644 --- a/src/main/kotlin/features/diana/DianaWaypoints.kt +++ b/src/main/kotlin/features/diana/DianaWaypoints.kt @@ -4,12 +4,14 @@ import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.AttackBlockEvent import moe.nea.firmament.events.UseBlockEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.Config +import moe.nea.firmament.util.data.ManagedConfig object DianaWaypoints : FirmamentFeature { override val identifier get() = "diana" override val config get() = TConfig + @Config object TConfig : ManagedConfig(identifier, Category.EVENTS) { val ancestralSpadeSolver by toggle("ancestral-spade") { true } val ancestralSpadeTeleport by keyBindingWithDefaultUnbound("ancestral-teleport") diff --git a/src/main/kotlin/features/events/anniversity/AnniversaryFeatures.kt b/src/main/kotlin/features/events/anniversity/AnniversaryFeatures.kt index c1900e9..e26b4c9 100644 --- a/src/main/kotlin/features/events/anniversity/AnniversaryFeatures.kt +++ b/src/main/kotlin/features/events/anniversity/AnniversaryFeatures.kt @@ -14,7 +14,7 @@ import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.events.TickEvent import moe.nea.firmament.events.WorldReadyEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.gui.hud.MoulConfigHud import moe.nea.firmament.repo.ExpensiveItemCacheApi import moe.nea.firmament.repo.ItemNameLookup @@ -23,6 +23,7 @@ import moe.nea.firmament.util.MC import moe.nea.firmament.util.SHORT_NUMBER_FORMAT import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.parseShortNumber import moe.nea.firmament.util.useMatch @@ -30,6 +31,7 @@ object AnniversaryFeatures : FirmamentFeature { override val identifier: String get() = "anniversary" + @Config object TConfig : ManagedConfig(identifier, Category.EVENTS) { val enableShinyPigTracker by toggle("shiny-pigs") {true} val trackPigCooldown by position("pig-hud", 200, 300) { Vector2i(100, 200) } diff --git a/src/main/kotlin/features/events/anniversity/CenturyRaffleFeatures.kt b/src/main/kotlin/features/events/anniversity/CenturyRaffleFeatures.kt index 9935051..9eb098a 100644 --- a/src/main/kotlin/features/events/anniversity/CenturyRaffleFeatures.kt +++ b/src/main/kotlin/features/events/anniversity/CenturyRaffleFeatures.kt @@ -8,14 +8,16 @@ import net.minecraft.text.Style import net.minecraft.util.Formatting import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.EntityRenderTintEvent -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC import moe.nea.firmament.util.SkyblockId +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.render.TintedOverlayTexture import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.skyblock.SkyBlockItems object CenturyRaffleFeatures { + @Config object TConfig : ManagedConfig("centuryraffle", Category.EVENTS) { val highlightPlayersForSlice by toggle("highlight-cake-players") { true } // val highlightAllPlayers by toggle("highlight-all-cake-players") { true } diff --git a/src/main/kotlin/features/events/carnival/CarnivalFeatures.kt b/src/main/kotlin/features/events/carnival/CarnivalFeatures.kt index 840fb8c..877b54b 100644 --- a/src/main/kotlin/features/events/carnival/CarnivalFeatures.kt +++ b/src/main/kotlin/features/events/carnival/CarnivalFeatures.kt @@ -2,10 +2,12 @@ package moe.nea.firmament.features.events.carnival import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.Config +import moe.nea.firmament.util.data.ManagedConfig object CarnivalFeatures : FirmamentFeature { - object TConfig : ManagedConfig(identifier, Category.EVENTS) { + @Config + object TConfig : ManagedConfig(identifier, Category.EVENTS) { val enableBombSolver by toggle("bombs-solver") { true } val displayTutorials by toggle("tutorials") { true } } diff --git a/src/main/kotlin/features/fixes/CompatibliltyFeatures.kt b/src/main/kotlin/features/fixes/CompatibliltyFeatures.kt index 76f6ed4..1858e87 100644 --- a/src/main/kotlin/features/fixes/CompatibliltyFeatures.kt +++ b/src/main/kotlin/features/fixes/CompatibliltyFeatures.kt @@ -5,13 +5,15 @@ 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.data.ManagedConfig import moe.nea.firmament.util.compatloader.CompatLoader +import moe.nea.firmament.util.data.Config object CompatibliltyFeatures : FirmamentFeature { override val identifier: String get() = "compatibility" + @Config object TConfig : ManagedConfig(identifier, Category.INTEGRATIONS) { val enhancedExplosions by toggle("explosion-enabled") { false } val explosionSize by integer("explosion-power", 10, 50) { 1 } diff --git a/src/main/kotlin/features/fixes/Fixes.kt b/src/main/kotlin/features/fixes/Fixes.kt index 0cb5a32..d3876a7 100644 --- a/src/main/kotlin/features/fixes/Fixes.kt +++ b/src/main/kotlin/features/fixes/Fixes.kt @@ -9,14 +9,16 @@ import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HudRenderEvent import moe.nea.firmament.events.WorldKeyboardEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.tr object Fixes : FirmamentFeature { override val identifier: String get() = "fixes" + @Config object TConfig : ManagedConfig(identifier, Category.MISC) { // TODO: split this config val fixUnsignedPlayerSkins by toggle("player-skins") { true } var autoSprint by toggle("auto-sprint") { false } diff --git a/src/main/kotlin/features/garden/HideComposterNoises.kt b/src/main/kotlin/features/garden/HideComposterNoises.kt index 69207a9..2e8eb76 100644 --- a/src/main/kotlin/features/garden/HideComposterNoises.kt +++ b/src/main/kotlin/features/garden/HideComposterNoises.kt @@ -5,11 +5,13 @@ import net.minecraft.sound.SoundEvent import net.minecraft.sound.SoundEvents import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.SoundReceiveEvent -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.SBData import moe.nea.firmament.util.SkyBlockIsland +import moe.nea.firmament.util.data.Config object HideComposterNoises { + @Config object TConfig : ManagedConfig("composter", Category.GARDEN) { val hideComposterNoises by toggle("no-more-noises") { false } } diff --git a/src/main/kotlin/features/inventory/ItemHotkeys.kt b/src/main/kotlin/features/inventory/ItemHotkeys.kt index e826b31..c6b5ca6 100644 --- a/src/main/kotlin/features/inventory/ItemHotkeys.kt +++ b/src/main/kotlin/features/inventory/ItemHotkeys.kt @@ -2,7 +2,7 @@ package moe.nea.firmament.features.inventory import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HandledScreenKeyPressedEvent -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.repo.ExpensiveItemCacheApi import moe.nea.firmament.repo.HypixelStaticData import moe.nea.firmament.repo.ItemCache @@ -11,11 +11,13 @@ import moe.nea.firmament.repo.ItemCache.isBroken import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.util.MC import moe.nea.firmament.util.asBazaarStock +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.focusedItemStack import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.skyblock.SBItemUtil.getSearchName object ItemHotkeys { + @Config object TConfig : ManagedConfig("item-hotkeys", Category.INVENTORY) { val openGlobalTradeInterface by keyBindingWithDefaultUnbound("global-trade-interface") } diff --git a/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt b/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt index 9dae118..196f948 100644 --- a/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt +++ b/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt @@ -11,9 +11,10 @@ import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HotbarItemRenderEvent import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.collections.lastNotNullOfOrNull import moe.nea.firmament.util.collections.memoizeIdentity +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.mc.loreAccordingToNbt import moe.nea.firmament.util.skyblock.Rarity import moe.nea.firmament.util.unformattedString @@ -22,6 +23,7 @@ object ItemRarityCosmetics : FirmamentFeature { override val identifier: String get() = "item-rarity-cosmetics" + @Config object TConfig : ManagedConfig(identifier, Category.INVENTORY) { val showItemRarityBackground by toggle("background") { false } val showItemRarityInHotbar by toggle("background-hotbar") { false } diff --git a/src/main/kotlin/features/inventory/JunkHighlighter.kt b/src/main/kotlin/features/inventory/JunkHighlighter.kt index 80fd99d..e5ab036 100644 --- a/src/main/kotlin/features/inventory/JunkHighlighter.kt +++ b/src/main/kotlin/features/inventory/JunkHighlighter.kt @@ -4,7 +4,8 @@ import org.lwjgl.glfw.GLFW import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.Config +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.skyblock.SBItemUtil.getSearchName import moe.nea.firmament.util.useMatch @@ -12,6 +13,7 @@ object JunkHighlighter : FirmamentFeature { override val identifier: String get() = "junk-highlighter" + @Config object TConfig : ManagedConfig(identifier, Category.INVENTORY) { val junkRegex by string("regex") { "" } val highlightBind by keyBinding("highlight") { GLFW.GLFW_KEY_LEFT_CONTROL } diff --git a/src/main/kotlin/features/inventory/PetFeatures.kt b/src/main/kotlin/features/inventory/PetFeatures.kt index 701d30c..5df4bc4 100644 --- a/src/main/kotlin/features/inventory/PetFeatures.kt +++ b/src/main/kotlin/features/inventory/PetFeatures.kt @@ -9,12 +9,13 @@ import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HudRenderEvent import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.jarvis.JarvisIntegration import moe.nea.firmament.util.FirmFormatters.formatPercent import moe.nea.firmament.util.FirmFormatters.shortFormat import moe.nea.firmament.util.MC import moe.nea.firmament.util.SBData +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.petData import moe.nea.firmament.util.render.drawGuiTexture import moe.nea.firmament.util.skyblock.Rarity @@ -29,6 +30,7 @@ object PetFeatures : FirmamentFeature { override val config: ManagedConfig? get() = TConfig + @Config object TConfig : ManagedConfig(identifier, Category.INVENTORY) { val highlightEquippedPet by toggle("highlight-pet") { true } var petOverlay by toggle("pet-overlay") { false } diff --git a/src/main/kotlin/features/inventory/PriceData.kt b/src/main/kotlin/features/inventory/PriceData.kt index 32e8a1f..ce5c7ea 100644 --- a/src/main/kotlin/features/inventory/PriceData.kt +++ b/src/main/kotlin/features/inventory/PriceData.kt @@ -6,12 +6,13 @@ import net.minecraft.util.StringIdentifiable 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 +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.repo.HypixelStaticData import moe.nea.firmament.util.FirmFormatters.formatCommas import moe.nea.firmament.util.asBazaarStock import moe.nea.firmament.util.bold import moe.nea.firmament.util.darkGrey +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.getLogicalStackSize import moe.nea.firmament.util.gold import moe.nea.firmament.util.skyBlockId @@ -22,6 +23,7 @@ object PriceData : FirmamentFeature { override val identifier: String get() = "price-data" + @Config object TConfig : ManagedConfig(identifier, Category.INVENTORY) { val tooltipEnabled by toggle("enable-always") { true } val enableKeybinding by keyBindingWithDefaultUnbound("enable-keybind") diff --git a/src/main/kotlin/features/inventory/REIDependencyWarner.kt b/src/main/kotlin/features/inventory/REIDependencyWarner.kt index 6bf2928..4bb93ee 100644 --- a/src/main/kotlin/features/inventory/REIDependencyWarner.kt +++ b/src/main/kotlin/features/inventory/REIDependencyWarner.kt @@ -77,7 +77,7 @@ object REIDependencyWarner { event.subcommand("disablereiwarning") { thenExecute { RepoManager.Config.warnForMissingItemListMod = false - RepoManager.Config.save() + RepoManager.Config.markDirty() MC.sendChat(Text.translatable("firmament.reiwarning.disabled").yellow()) } } diff --git a/src/main/kotlin/features/inventory/SaveCursorPosition.kt b/src/main/kotlin/features/inventory/SaveCursorPosition.kt index bbd216c..2a08730 100644 --- a/src/main/kotlin/features/inventory/SaveCursorPosition.kt +++ b/src/main/kotlin/features/inventory/SaveCursorPosition.kt @@ -7,15 +7,17 @@ import kotlin.math.absoluteValue import kotlin.time.Duration.Companion.milliseconds import net.minecraft.client.util.InputUtil import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC import moe.nea.firmament.util.TimeMark import moe.nea.firmament.util.assertNotNullOr +import moe.nea.firmament.util.data.Config object SaveCursorPosition : FirmamentFeature { override val identifier: String get() = "save-cursor-position" + @Config object TConfig : ManagedConfig(identifier, Category.INVENTORY) { val enable by toggle("enable") { true } val tolerance by duration("tolerance", 10.milliseconds, 5000.milliseconds) { 500.milliseconds } diff --git a/src/main/kotlin/features/inventory/SlotLocking.kt b/src/main/kotlin/features/inventory/SlotLocking.kt index b4cd535..8be7bdb 100644 --- a/src/main/kotlin/features/inventory/SlotLocking.kt +++ b/src/main/kotlin/features/inventory/SlotLocking.kt @@ -34,7 +34,7 @@ import moe.nea.firmament.events.IsSlotProtectedEvent import moe.nea.firmament.events.ScreenChangeEvent import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.keybindings.InputModifiers import moe.nea.firmament.keybindings.SavedKeyBinding import moe.nea.firmament.mixins.accessor.AccessorHandledScreen @@ -42,6 +42,7 @@ import moe.nea.firmament.util.CommonSoundEffects import moe.nea.firmament.util.MC import moe.nea.firmament.util.SBData import moe.nea.firmament.util.SkyBlockIsland +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.data.ProfileSpecificDataHolder import moe.nea.firmament.util.extraAttributes import moe.nea.firmament.util.json.DashlessUUIDSerializer @@ -140,6 +141,7 @@ object SlotLocking : FirmamentFeature { } + @Config object TConfig : ManagedConfig(identifier, Category.INVENTORY) { val lockSlot by keyBinding("lock") { GLFW.GLFW_KEY_L } val lockUUID by keyBindingWithOutDefaultModifiers("lock-uuid") { diff --git a/src/main/kotlin/features/inventory/TimerInLore.kt b/src/main/kotlin/features/inventory/TimerInLore.kt index e939404..eb1463b 100644 --- a/src/main/kotlin/features/inventory/TimerInLore.kt +++ b/src/main/kotlin/features/inventory/TimerInLore.kt @@ -11,9 +11,10 @@ import net.minecraft.text.Text import net.minecraft.util.StringIdentifiable import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ItemTooltipEvent -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.SBData import moe.nea.firmament.util.aqua +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.grey import moe.nea.firmament.util.mc.displayNameAccordingToNbt import moe.nea.firmament.util.timestamp @@ -21,6 +22,7 @@ import moe.nea.firmament.util.tr import moe.nea.firmament.util.unformattedString object TimerInLore { + @Config object TConfig : ManagedConfig("lore-timers", Category.INVENTORY) { val showTimers by toggle("show") { true } val showCreationTimestamp by toggle("show-creation") { true } diff --git a/src/main/kotlin/features/inventory/WardrobeKeybinds.kt b/src/main/kotlin/features/inventory/WardrobeKeybinds.kt index 377afd3..ca5ff3a 100644 --- a/src/main/kotlin/features/inventory/WardrobeKeybinds.kt +++ b/src/main/kotlin/features/inventory/WardrobeKeybinds.kt @@ -5,11 +5,13 @@ import net.minecraft.item.Items import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HandledScreenKeyPressedEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.mc.SlotUtils.clickLeftMouseButton object WardrobeKeybinds { + @Config object TConfig : ManagedConfig("wardrobe-keybinds", Category.INVENTORY) { val wardrobeKeybinds by toggle("wardrobe-keybinds") { false } val changePageKeybind by keyBinding("change-page") { GLFW.GLFW_KEY_ENTER } diff --git a/src/main/kotlin/features/inventory/buttons/InventoryButtons.kt b/src/main/kotlin/features/inventory/buttons/InventoryButtons.kt index 46e91b2..f49e6ab 100644 --- a/src/main/kotlin/features/inventory/buttons/InventoryButtons.kt +++ b/src/main/kotlin/features/inventory/buttons/InventoryButtons.kt @@ -13,16 +13,18 @@ import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HandledScreenClickEvent import moe.nea.firmament.events.HandledScreenForegroundEvent import moe.nea.firmament.events.HandledScreenPushREIEvent -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC import moe.nea.firmament.util.ScreenUtil import moe.nea.firmament.util.TimeMark import moe.nea.firmament.util.data.DataHolder import moe.nea.firmament.util.accessors.getRectangle +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.gold object InventoryButtons { + @Config object TConfig : ManagedConfig("inventory-buttons-config", Category.INVENTORY) { val _openEditor by button("open-editor") { openEditor() diff --git a/src/main/kotlin/features/inventory/storageoverlay/StorageOverlay.kt b/src/main/kotlin/features/inventory/storageoverlay/StorageOverlay.kt index f59b293..3734024 100644 --- a/src/main/kotlin/features/inventory/storageoverlay/StorageOverlay.kt +++ b/src/main/kotlin/features/inventory/storageoverlay/StorageOverlay.kt @@ -14,9 +14,10 @@ import moe.nea.firmament.events.SlotClickEvent import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.events.TickEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC import moe.nea.firmament.util.customgui.customGui +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.data.ProfileSpecificDataHolder object StorageOverlay : FirmamentFeature { @@ -27,6 +28,7 @@ object StorageOverlay : FirmamentFeature { override val identifier: String get() = "storage-overlay" + @Config object TConfig : ManagedConfig(identifier, Category.INVENTORY) { val alwaysReplace by toggle("always-replace") { true } val outlineActiveStoragePage by toggle("outline-active-page") { false } diff --git a/src/main/kotlin/features/items/BlockZapperOverlay.kt b/src/main/kotlin/features/items/BlockZapperOverlay.kt index c207d67..ad96b8e 100644 --- a/src/main/kotlin/features/items/BlockZapperOverlay.kt +++ b/src/main/kotlin/features/items/BlockZapperOverlay.kt @@ -13,8 +13,9 @@ import moe.nea.firmament.events.ClientStartedEvent import moe.nea.firmament.events.WorldKeyboardEvent import moe.nea.firmament.events.WorldRenderLastEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.render.RenderInWorldContext import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.skyblock.SkyBlockItems @@ -23,6 +24,7 @@ object BlockZapperOverlay : FirmamentFeature { override val identifier: String get() = "block-zapper-overlay" + @Config object TConfig : ManagedConfig(identifier, Category.ITEMS) { var blockZapperOverlay by toggle("block-zapper-overlay") { false } val color by colour("color") { ChromaColour.fromStaticRGB(160, 0, 0, 60) } diff --git a/src/main/kotlin/features/items/BonemerangOverlay.kt b/src/main/kotlin/features/items/BonemerangOverlay.kt index 6483b7a..80019c0 100644 --- a/src/main/kotlin/features/items/BonemerangOverlay.kt +++ b/src/main/kotlin/features/items/BonemerangOverlay.kt @@ -13,8 +13,9 @@ import moe.nea.firmament.events.ClientStartedEvent import moe.nea.firmament.events.EntityRenderTintEvent import moe.nea.firmament.events.HudRenderEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.render.TintedOverlayTexture import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.skyblock.SkyBlockItems @@ -24,6 +25,7 @@ object BonemerangOverlay : FirmamentFeature { override val identifier: String get() = "bonemerang-overlay" + @Config object TConfig : ManagedConfig(identifier, Category.ITEMS) { var bonemerangOverlay by toggle("bonemerang-overlay") { false } val bonemerangOverlayHud by position("bonemerang-overlay-hud", 80, 10) { Vector2i() } diff --git a/src/main/kotlin/features/items/EtherwarpOverlay.kt b/src/main/kotlin/features/items/EtherwarpOverlay.kt index 8893339..640c8f5 100644 --- a/src/main/kotlin/features/items/EtherwarpOverlay.kt +++ b/src/main/kotlin/features/items/EtherwarpOverlay.kt @@ -14,9 +14,10 @@ import net.minecraft.world.BlockView import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.WorldRenderLastEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC import moe.nea.firmament.util.SBData +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.extraAttributes import moe.nea.firmament.util.render.RenderInWorldContext import moe.nea.firmament.util.skyBlockId @@ -27,6 +28,7 @@ object EtherwarpOverlay : FirmamentFeature { override val identifier: String get() = "etherwarp-overlay" + @Config object TConfig : ManagedConfig(identifier, Category.ITEMS) { var etherwarpOverlay by toggle("etherwarp-overlay") { false } var onlyShowWhileSneaking by toggle("only-show-while-sneaking") { true } diff --git a/src/main/kotlin/features/macros/ComboProcessor.kt b/src/main/kotlin/features/macros/ComboProcessor.kt index 03e9238..2b979c3 100644 --- a/src/main/kotlin/features/macros/ComboProcessor.kt +++ b/src/main/kotlin/features/macros/ComboProcessor.kt @@ -24,12 +24,6 @@ object ComboProcessor { var lastInput = TimeMark.farPast() val breadCrumbs = mutableListOf<SavedKeyBinding>() - init { - setActions( - MacroData.DConfig.data.comboActions - ) - } - fun setActions(actions: List<ComboKeyAction>) { rootTrie = KeyComboTrie.fromComboList(actions) reset() diff --git a/src/main/kotlin/features/macros/MacroData.kt b/src/main/kotlin/features/macros/MacroData.kt index 91de423..447516e 100644 --- a/src/main/kotlin/features/macros/MacroData.kt +++ b/src/main/kotlin/features/macros/MacroData.kt @@ -8,5 +8,10 @@ data class MacroData( var comboActions: List<ComboKeyAction> = listOf(), var wheels: List<MacroWheel> = listOf(), ) { - object DConfig : DataHolder<MacroData>(kotlinx.serialization.serializer(), "macros", ::MacroData) + object DConfig : DataHolder<MacroData>(kotlinx.serialization.serializer(), "macros", ::MacroData) { + override fun onLoad() { + ComboProcessor.setActions(data.comboActions) + RadialMacros.setWheels(data.wheels) + } + } } diff --git a/src/main/kotlin/features/macros/RadialMenu.kt b/src/main/kotlin/features/macros/RadialMenu.kt index 3496d43..43e65a7 100644 --- a/src/main/kotlin/features/macros/RadialMenu.kt +++ b/src/main/kotlin/features/macros/RadialMenu.kt @@ -1,5 +1,6 @@ package moe.nea.firmament.features.macros +import me.shedaniel.math.Color import org.joml.Vector2f import util.render.CustomRenderLayers import kotlin.math.atan2 @@ -93,7 +94,7 @@ object RadialMenuViewer { option.renderSlice(event.context) mat.popMatrix() } - event.context.drawLine(1, 1, delta.x.toInt(), delta.y.toInt(), me.shedaniel.math.Color.ofOpaque(0x00FF00)) + event.context.drawLine(1, 1, delta.x.toInt(), delta.y.toInt(), Color.ofOpaque(0x00FF00)) mat.popMatrix() } @@ -115,7 +116,7 @@ object RadialMenuViewer { } object RadialMacros { - var wheels = MacroData.DConfig.data.wheels + lateinit var wheels: List<MacroWheel> private set fun setWheels(wheels: List<MacroWheel>) { diff --git a/src/main/kotlin/features/mining/CommissionFeatures.kt b/src/main/kotlin/features/mining/CommissionFeatures.kt index faba253..05658cc 100644 --- a/src/main/kotlin/features/mining/CommissionFeatures.kt +++ b/src/main/kotlin/features/mining/CommissionFeatures.kt @@ -3,20 +3,22 @@ package moe.nea.firmament.features.mining import moe.nea.firmament.Firmament import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.SlotRenderEvents -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.mc.loreAccordingToNbt import moe.nea.firmament.util.unformattedString object CommissionFeatures { - object Config : ManagedConfig("commissions", Category.MINING) { + @Config + object TConfig : ManagedConfig("commissions", Category.MINING) { val highlightCompletedCommissions by toggle("highlight-completed") { true } } @Subscribe fun onSlotRender(event: SlotRenderEvents.Before) { - if (!Config.highlightCompletedCommissions) return + if (!TConfig.highlightCompletedCommissions) return if (MC.screenName != "Commissions") return val stack = event.slot.stack if (stack.loreAccordingToNbt.any { it.unformattedString == "COMPLETED" }) { diff --git a/src/main/kotlin/features/mining/HotmPresets.kt b/src/main/kotlin/features/mining/HotmPresets.kt index 2241fee..763364e 100644 --- a/src/main/kotlin/features/mining/HotmPresets.kt +++ b/src/main/kotlin/features/mining/HotmPresets.kt @@ -18,7 +18,7 @@ import moe.nea.firmament.events.ChestInventoryUpdateEvent import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.events.ScreenChangeEvent import moe.nea.firmament.events.SlotRenderEvents -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.mixins.accessor.AccessorHandledScreen import moe.nea.firmament.util.ClipboardUtils import moe.nea.firmament.util.MC diff --git a/src/main/kotlin/features/mining/PickaxeAbility.kt b/src/main/kotlin/features/mining/PickaxeAbility.kt index de50217..3acdcc3 100644 --- a/src/main/kotlin/features/mining/PickaxeAbility.kt +++ b/src/main/kotlin/features/mining/PickaxeAbility.kt @@ -19,7 +19,7 @@ import moe.nea.firmament.events.SlotClickEvent import moe.nea.firmament.events.UseItemEvent import moe.nea.firmament.events.WorldReadyEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.DurabilityBarEvent import moe.nea.firmament.util.MC import moe.nea.firmament.util.SBData @@ -27,6 +27,7 @@ import moe.nea.firmament.util.SHORT_NUMBER_FORMAT import moe.nea.firmament.util.SkyBlockIsland import moe.nea.firmament.util.TIME_PATTERN import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.extraAttributes import moe.nea.firmament.util.mc.displayNameAccordingToNbt import moe.nea.firmament.util.mc.loreAccordingToNbt @@ -62,6 +63,7 @@ object PickaxeAbility : FirmamentFeature { fun matches(type: ItemType) = items.contains(type) } + @Config object TConfig : ManagedConfig(identifier, Category.MINING) { val cooldownEnabled by toggle("ability-cooldown") { false } val disableInDungeons by toggle("disable-in-dungeons") { true } diff --git a/src/main/kotlin/features/mining/PristineProfitTracker.kt b/src/main/kotlin/features/mining/PristineProfitTracker.kt index eb3cba6..e63a107 100644 --- a/src/main/kotlin/features/mining/PristineProfitTracker.kt +++ b/src/main/kotlin/features/mining/PristineProfitTracker.kt @@ -10,12 +10,13 @@ import net.minecraft.text.Text import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.gui.hud.MoulConfigHud import moe.nea.firmament.util.BazaarPriceStrategy import moe.nea.firmament.util.FirmFormatters.formatCommas import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.StringUtil.parseIntWithComma +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.data.ProfileSpecificDataHolder import moe.nea.firmament.util.formattedString import moe.nea.firmament.util.useMatch @@ -56,6 +57,7 @@ object PristineProfitTracker : FirmamentFeature { override val config: ManagedConfig? get() = TConfig + @Config object TConfig : ManagedConfig(identifier, Category.MINING) { val timeout by duration("timeout", 0.seconds, 120.seconds) { 30.seconds } val gui by position("position", 100, 30) { Vector2i() } diff --git a/src/main/kotlin/features/misc/CustomCapes.kt b/src/main/kotlin/features/misc/CustomCapes.kt index a5bc52a..f59f715 100644 --- a/src/main/kotlin/features/misc/CustomCapes.kt +++ b/src/main/kotlin/features/misc/CustomCapes.kt @@ -23,15 +23,17 @@ import net.minecraft.client.util.math.MatrixStack import net.minecraft.util.Identifier import moe.nea.firmament.Firmament import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.mc.CustomRenderPassHelper object CustomCapes : FirmamentFeature { override val identifier: String get() = "developer-capes" + @Config object TConfig : ManagedConfig(identifier, Category.DEV) { val showCapes by toggle("show-cape") { true } } diff --git a/src/main/kotlin/features/misc/Hud.kt b/src/main/kotlin/features/misc/Hud.kt index 8c785ab..272c349 100644 --- a/src/main/kotlin/features/misc/Hud.kt +++ b/src/main/kotlin/features/misc/Hud.kt @@ -3,18 +3,20 @@ package moe.nea.firmament.features.misc import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HudRenderEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC import moe.nea.firmament.util.tr import moe.nea.jarvis.api.Point import org.joml.Vector2i import net.minecraft.client.network.PlayerListEntry import net.minecraft.text.Text +import moe.nea.firmament.util.data.Config object Hud : FirmamentFeature { override val identifier: String get() = "hud" + @Config object TConfig : ManagedConfig(identifier, Category.MISC) { var dayCount by toggle("day-count") { false } val dayCountHud by position("day-count-hud", 80, 10) { Vector2i() } diff --git a/src/main/kotlin/features/world/FairySouls.kt b/src/main/kotlin/features/world/FairySouls.kt index 699aafc..477fbe6 100644 --- a/src/main/kotlin/features/world/FairySouls.kt +++ b/src/main/kotlin/features/world/FairySouls.kt @@ -14,12 +14,13 @@ import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.events.SkyblockServerUpdateEvent import moe.nea.firmament.events.WorldRenderLastEvent import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.util.MC import moe.nea.firmament.util.SBData import moe.nea.firmament.util.SkyBlockIsland import moe.nea.firmament.util.blockPos +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.data.ProfileSpecificDataHolder import moe.nea.firmament.util.render.RenderInWorldContext import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld @@ -37,9 +38,10 @@ object FairySouls : FirmamentFeature { override val config: ManagedConfig get() = TConfig + @Config object DConfig : ProfileSpecificDataHolder<Data>(serializer(), "found-fairysouls", ::Data) - + @Config object TConfig : ManagedConfig("fairy-souls", Category.MISC) { val displaySouls by toggle("show") { false } val resetSouls by button("reset") { diff --git a/src/main/kotlin/features/world/Waypoints.kt b/src/main/kotlin/features/world/Waypoints.kt index 205d5eb..72bd9e8 100644 --- a/src/main/kotlin/features/world/Waypoints.kt +++ b/src/main/kotlin/features/world/Waypoints.kt @@ -17,8 +17,9 @@ import moe.nea.firmament.events.TickEvent 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 +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.mc.asFakeServer import moe.nea.firmament.util.render.RenderInWorldContext import moe.nea.firmament.util.tr @@ -27,6 +28,7 @@ object Waypoints : FirmamentFeature { override val identifier: String get() = "waypoints" + @Config object TConfig : ManagedConfig(identifier, Category.MINING) { // TODO: add to misc val tempWaypointDuration by duration("temp-waypoint-duration", 0.seconds, 1.hours) { 30.seconds } val showIndex by toggle("show-index") { true } diff --git a/src/main/kotlin/gui/config/AllConfigsGui.kt b/src/main/kotlin/gui/config/AllConfigsGui.kt index f9ffd2d..0add10f 100644 --- a/src/main/kotlin/gui/config/AllConfigsGui.kt +++ b/src/main/kotlin/gui/config/AllConfigsGui.kt @@ -10,9 +10,11 @@ import moe.nea.firmament.commands.get import moe.nea.firmament.commands.thenArgument import moe.nea.firmament.commands.thenExecute import moe.nea.firmament.events.CommandEvent +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.MC import moe.nea.firmament.util.MoulConfigUtils import moe.nea.firmament.util.ScreenUtil.setScreenLater +import moe.nea.firmament.util.data.Config object AllConfigsGui { // @@ -21,6 +23,7 @@ object AllConfigsGui { // RepoManager.Config // ) + FeatureManager.allFeatures.mapNotNull { it.config } + @Config object ConfigConfig : ManagedConfig("configconfig", Category.META) { val enableYacl by toggle("enable-yacl") { false } val enableMoulConfig by toggle("enable-moulconfig") { true } diff --git a/src/main/kotlin/gui/config/BooleanHandler.kt b/src/main/kotlin/gui/config/BooleanHandler.kt index 8592777..b954401 100644 --- a/src/main/kotlin/gui/config/BooleanHandler.kt +++ b/src/main/kotlin/gui/config/BooleanHandler.kt @@ -9,6 +9,7 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.boolean import kotlinx.serialization.json.jsonPrimitive +import moe.nea.firmament.util.data.ManagedConfig class BooleanHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Boolean> { override fun toJson(element: Boolean): JsonElement? { @@ -29,7 +30,7 @@ class BooleanHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Bo override fun set(newValue: Boolean) { opt.set(newValue) - config.save() + config.markDirty() } }, 200) )) diff --git a/src/main/kotlin/gui/config/ChoiceHandler.kt b/src/main/kotlin/gui/config/ChoiceHandler.kt index 2ea3efc..9c3dda2 100644 --- a/src/main/kotlin/gui/config/ChoiceHandler.kt +++ b/src/main/kotlin/gui/config/ChoiceHandler.kt @@ -9,6 +9,7 @@ import kotlinx.serialization.json.JsonElement import kotlin.jvm.optionals.getOrNull import net.minecraft.util.StringIdentifiable import moe.nea.firmament.gui.CheckboxComponent +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.ErrorUtil import moe.nea.firmament.util.json.KJsonOps diff --git a/src/main/kotlin/gui/config/ClickHandler.kt b/src/main/kotlin/gui/config/ClickHandler.kt index fa1c621..9ea83aa 100644 --- a/src/main/kotlin/gui/config/ClickHandler.kt +++ b/src/main/kotlin/gui/config/ClickHandler.kt @@ -5,6 +5,7 @@ package moe.nea.firmament.gui.config import io.github.notenoughupdates.moulconfig.gui.component.TextComponent import kotlinx.serialization.json.JsonElement import moe.nea.firmament.gui.FirmButtonComponent +import moe.nea.firmament.util.data.ManagedConfig class ClickHandler(val config: ManagedConfig, val runnable: () -> Unit) : ManagedConfig.OptionHandler<Unit> { override fun toJson(element: Unit): JsonElement? { diff --git a/src/main/kotlin/gui/config/ColourHandler.kt b/src/main/kotlin/gui/config/ColourHandler.kt index 83ce8ac..33daa6d 100644 --- a/src/main/kotlin/gui/config/ColourHandler.kt +++ b/src/main/kotlin/gui/config/ColourHandler.kt @@ -10,6 +10,7 @@ import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement +import moe.nea.firmament.util.data.ManagedConfig class ColourHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<ChromaColour> { @@ -73,7 +74,7 @@ class ColourHandler(val config: ManagedConfig) : opt.value.toLegacyString(), { opt.value = ChromaColour.forLegacyString(it) - config.save() + config.markDirty() }, { } ) diff --git a/src/main/kotlin/gui/config/DurationHandler.kt b/src/main/kotlin/gui/config/DurationHandler.kt index 32bec25..4800bf6 100644 --- a/src/main/kotlin/gui/config/DurationHandler.kt +++ b/src/main/kotlin/gui/config/DurationHandler.kt @@ -12,6 +12,7 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.long +import moe.nea.firmament.util.data.ManagedConfig import kotlin.time.Duration import kotlin.time.DurationUnit import kotlin.time.toDuration diff --git a/src/main/kotlin/gui/config/HudMetaHandler.kt b/src/main/kotlin/gui/config/HudMetaHandler.kt index 0637351..dcf5d8f 100644 --- a/src/main/kotlin/gui/config/HudMetaHandler.kt +++ b/src/main/kotlin/gui/config/HudMetaHandler.kt @@ -10,6 +10,7 @@ import net.minecraft.text.MutableText import net.minecraft.text.Text import moe.nea.firmament.Firmament import moe.nea.firmament.gui.FirmButtonComponent +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.jarvis.JarvisIntegration import moe.nea.firmament.util.MC diff --git a/src/main/kotlin/gui/config/IntegerHandler.kt b/src/main/kotlin/gui/config/IntegerHandler.kt index fd10447..3e7be57 100644 --- a/src/main/kotlin/gui/config/IntegerHandler.kt +++ b/src/main/kotlin/gui/config/IntegerHandler.kt @@ -12,6 +12,7 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.int import kotlinx.serialization.json.jsonPrimitive +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.FirmFormatters class IntegerHandler(val config: ManagedConfig, val min: Int, val max: Int) : ManagedConfig.OptionHandler<Int> { diff --git a/src/main/kotlin/gui/config/KeyBindingHandler.kt b/src/main/kotlin/gui/config/KeyBindingHandler.kt index 14a4b32..a5e626d 100644 --- a/src/main/kotlin/gui/config/KeyBindingHandler.kt +++ b/src/main/kotlin/gui/config/KeyBindingHandler.kt @@ -11,6 +11,7 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.decodeFromJsonElement import kotlinx.serialization.json.encodeToJsonElement import moe.nea.firmament.gui.FirmButtonComponent +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.keybindings.FirmamentKeyBindings import moe.nea.firmament.keybindings.SavedKeyBinding @@ -35,7 +36,7 @@ class KeyBindingHandler(val name: String, val managedConfig: ManagedConfig) : { opt.value }, { opt.value = it - opt.element.save() + opt.element.markDirty() }, { button.blur() }, { button.requestFocus() } diff --git a/src/main/kotlin/gui/config/ManagedConfigElement.kt b/src/main/kotlin/gui/config/ManagedConfigElement.kt deleted file mode 100644 index 28cd6b8..0000000 --- a/src/main/kotlin/gui/config/ManagedConfigElement.kt +++ /dev/null @@ -1,8 +0,0 @@ - - -package moe.nea.firmament.gui.config - -abstract class ManagedConfigElement { - abstract val name: String - -} diff --git a/src/main/kotlin/gui/config/ManagedOption.kt b/src/main/kotlin/gui/config/ManagedOption.kt index 830086c..888b3f1 100644 --- a/src/main/kotlin/gui/config/ManagedOption.kt +++ b/src/main/kotlin/gui/config/ManagedOption.kt @@ -3,6 +3,7 @@ package moe.nea.firmament.gui.config import io.github.notenoughupdates.moulconfig.observer.GetSetter import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject +import moe.nea.firmament.util.data.ManagedConfig import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import net.minecraft.text.Text @@ -27,11 +28,11 @@ class ManagedOption<T : Any>( val descriptionTranslationKey = "firmament.config.${element.name}.${propertyName}.description" val labelDescription: Text = Text.translatable(descriptionTranslationKey) - private var actualValue: T? = null + var _actualValue: T? = null var value: T - get() = actualValue ?: error("Lateinit variable not initialized") + get() = _actualValue ?: error("Lateinit variable not initialized") set(value) { - actualValue = value + _actualValue = value element.onChange(this) } diff --git a/src/main/kotlin/gui/config/StringHandler.kt b/src/main/kotlin/gui/config/StringHandler.kt index a326abb..da14d4b 100644 --- a/src/main/kotlin/gui/config/StringHandler.kt +++ b/src/main/kotlin/gui/config/StringHandler.kt @@ -7,6 +7,7 @@ import io.github.notenoughupdates.moulconfig.observer.GetSetter import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonPrimitive +import moe.nea.firmament.util.data.ManagedConfig import net.minecraft.text.Text class StringHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<String> { @@ -25,7 +26,7 @@ class StringHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Str object : GetSetter<String> by opt { override fun set(newValue: String) { opt.set(newValue) - config.save() + config.markDirty() } }, 130, diff --git a/src/main/kotlin/gui/config/storage/ConfigLoadContext.kt b/src/main/kotlin/gui/config/storage/ConfigLoadContext.kt new file mode 100644 index 0000000..59afaa1 --- /dev/null +++ b/src/main/kotlin/gui/config/storage/ConfigLoadContext.kt @@ -0,0 +1,65 @@ +package moe.nea.firmament.gui.config.storage + +import java.io.PrintWriter +import java.nio.file.Path +import org.apache.commons.io.output.StringBuilderWriter +import kotlin.io.path.Path +import kotlin.io.path.createParentDirectories +import kotlin.io.path.writeText +import moe.nea.firmament.Firmament + +data class ConfigLoadContext( + val loadId: String, +) : AutoCloseable { + val logFile = Path("logs") + .resolve(Firmament.MOD_ID) + .resolve("config-$loadId.log") + .toAbsolutePath() + val logBuffer = StringBuilder() + + var shouldSaveLogBuffer = false + fun markShouldSaveLogBuffer() { + shouldSaveLogBuffer = true + } + + fun logDebug(message: String) { + logBuffer.append("[DEBUG] ").append(message).appendLine() + } + + fun logInfo(message: String) { + Firmament.logger.info("[ConfigUpgrade] $message") + logBuffer.append("[INFO] ").append(message).appendLine() + } + + fun logError(message: String, exception: Throwable) { + markShouldSaveLogBuffer() + Firmament.logger.error("[ConfigUpgrade] $message", exception) + logBuffer.append("[ERROR] ").append(message).appendLine() + PrintWriter(StringBuilderWriter(logBuffer)).use { + exception.printStackTrace(it) + } + logBuffer.appendLine() + } + + fun logError(message: String) { + markShouldSaveLogBuffer() + Firmament.logger.error("[ConfigUpgrade] $message") + logBuffer.append("[ERROR] ").append(message).appendLine() + } + + fun ensureWritable(path: Path) { + path.createParentDirectories() + } + + override fun close() { + logInfo("Closing out config load.") + if (shouldSaveLogBuffer) { + try { + ensureWritable(logFile) + logFile.writeText(logBuffer.toString()) + } catch (ex: Exception) { + logError("Could not save config load log", ex) + } + } + } +} diff --git a/src/main/kotlin/gui/config/storage/ConfigStorageClass.kt b/src/main/kotlin/gui/config/storage/ConfigStorageClass.kt new file mode 100644 index 0000000..8258fe7 --- /dev/null +++ b/src/main/kotlin/gui/config/storage/ConfigStorageClass.kt @@ -0,0 +1,8 @@ +package moe.nea.firmament.gui.config.storage + +enum class ConfigStorageClass { // TODO: make this encode type info somehow + PROFILE, + STORAGE, + CONFIG, +} + diff --git a/src/main/kotlin/gui/config/storage/FirmamentConfigLoader.kt b/src/main/kotlin/gui/config/storage/FirmamentConfigLoader.kt new file mode 100644 index 0000000..22cba2c --- /dev/null +++ b/src/main/kotlin/gui/config/storage/FirmamentConfigLoader.kt @@ -0,0 +1,204 @@ +package moe.nea.firmament.gui.config.storage + +import java.util.UUID +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.jsonObject +import kotlin.io.path.Path +import kotlin.io.path.exists +import kotlin.io.path.forEachDirectoryEntry +import kotlin.io.path.isDirectory +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.name +import kotlin.io.path.readText +import kotlin.io.path.writeText +import moe.nea.firmament.util.data.IConfigProvider +import moe.nea.firmament.util.data.IDataHolder +import moe.nea.firmament.util.data.ProfileKeyedConfig +import moe.nea.firmament.util.json.intoGson +import moe.nea.firmament.util.json.intoKotlinJson + +object FirmamentConfigLoader { + val currentConfigVersion = 1000 + val configFolder = Path("config/firmament") + .toAbsolutePath() + val storageFolder = configFolder.resolve("storage") + val profilePath = configFolder.resolve("profiles") + val tagLines = listOf( + "<- your config version here", + "I'm a teapot", + "mail.example.com ESMTP", + "Apples" + ) + val configVersionFile = configFolder.resolve("config.version") + + fun loadConfig() { + if (configFolder.exists()) { + if (!configVersionFile.exists()) { + LegacyImporter.importFromLegacy() + } + updateConfigs() + } + + ConfigLoadContext("load-${System.currentTimeMillis()}").use { loadContext -> + val configData = FirstLevelSplitJsonFolder(loadContext, configFolder).load() + loadConfigFromData(configData, Unit, ConfigStorageClass.CONFIG) + val storageData = FirstLevelSplitJsonFolder(loadContext, storageFolder).load() + loadConfigFromData(storageData, Unit, ConfigStorageClass.STORAGE) + val profileData = + profilePath.listDirectoryEntries() + .filter { it.isDirectory() } + .associate { + UUID.fromString(it.name) to FirstLevelSplitJsonFolder(loadContext, it).load() + } + profileData.forEach { (key, value) -> + loadConfigFromData(value, key, ConfigStorageClass.PROFILE) + } + } + } + + fun <T> loadConfigFromData( + configData: JsonObject, + key: T, + storageClass: ConfigStorageClass + ) { + for (holder in allConfigs) { + if (holder.storageClass == storageClass) { + (holder as IDataHolder<T>).loadFrom(key, configData) + } + } + } + + fun <T> collectConfigFromData( + key: T, + storageClass: ConfigStorageClass, + ): JsonObject { + var json = JsonObject(mapOf()) + for (holder in allConfigs) { + if (holder.storageClass == storageClass) { + json = mergeJson(json, (holder as IDataHolder<T>).saveTo(key)) + } + } + return json + } + + fun <T> saveStorage( + storageClass: ConfigStorageClass, + key: T, + firstLevelSplitJsonFolder: FirstLevelSplitJsonFolder, + ) { + firstLevelSplitJsonFolder.save( + collectConfigFromData(key, storageClass) + ) + } + + fun collectAllProfileIds(): Set<UUID> { + return allConfigs + .filter { it.storageClass == ConfigStorageClass.PROFILE } + .flatMapTo(mutableSetOf()) { + (it as ProfileKeyedConfig<*>).keys() + } + } + + fun saveAll() { + ConfigLoadContext("load-${System.currentTimeMillis()}").use { context -> + saveStorage( + ConfigStorageClass.CONFIG, + Unit, + FirstLevelSplitJsonFolder(context, configFolder) + ) + saveStorage( + ConfigStorageClass.STORAGE, + Unit, + FirstLevelSplitJsonFolder(context, storageFolder) + ) + collectAllProfileIds().forEach { profileId -> + saveStorage( + ConfigStorageClass.PROFILE, + profileId, + FirstLevelSplitJsonFolder(context, profilePath.resolve(profileId.toString())) + ) + } + } + } + + fun mergeJson(a: JsonObject, b: JsonObject): JsonObject { + fun mergeInner(a: JsonElement?, b: JsonElement?): JsonElement { + if (a == null) + return b!! + if (b == null) + return a + a as JsonObject + b as JsonObject + return buildJsonObject { + (a.keys + b.keys) + .forEach { + put(it, mergeInner(a[it], b[it])) + } + } + } + return mergeInner(a, b) as JsonObject + } + + val allConfigs: List<IDataHolder<*>> = IConfigProvider.providers.allValidInstances.flatMap { it.configs } + + fun updateConfigs() { + val startVersion = configVersionFile.readText() + .substringBefore(' ') + .trim() + .toInt() + ConfigLoadContext("update-from-$startVersion-to-$currentConfigVersion-${System.currentTimeMillis()}") + .use { loadContext -> + updateOneConfig( + loadContext, + startVersion, + ConfigStorageClass.CONFIG, + FirstLevelSplitJsonFolder(loadContext, configFolder) + ) + updateOneConfig( + loadContext, + startVersion, + ConfigStorageClass.STORAGE, + FirstLevelSplitJsonFolder(loadContext, storageFolder) + ) + profilePath.forEachDirectoryEntry { + updateOneConfig( + loadContext, + startVersion, + ConfigStorageClass.PROFILE, + FirstLevelSplitJsonFolder(loadContext, it) + ) + } + configVersionFile.writeText("$currentConfigVersion ${tagLines.random()}") + } + } + + private fun updateOneConfig( + loadContext: ConfigLoadContext, + startVersion: Int, + storageClass: ConfigStorageClass, + firstLevelSplitJsonFolder: FirstLevelSplitJsonFolder + ) { + loadContext.logInfo("Starting upgrade from at ${firstLevelSplitJsonFolder.folder} ($storageClass) to $startVersion") + var data = firstLevelSplitJsonFolder.load() + for (nextVersion in (startVersion + 1)..currentConfigVersion) { + data = updateOneConfigOnce(nextVersion, storageClass, data) + } + firstLevelSplitJsonFolder.save(data) + } + + private fun updateOneConfigOnce( + nextVersion: Int, + storageClass: ConfigStorageClass, + data: JsonObject + ): JsonObject { + return ConfigFixEvent.publish(ConfigFixEvent(storageClass, nextVersion, data.intoGson().asJsonObject)) + .data.intoKotlinJson().jsonObject + } + + fun markDirty(holder: IDataHolder<*>) { + TODO("Not yet implemented") + } + +} diff --git a/src/main/kotlin/gui/config/storage/FirstLevelSplitJsonFolder.kt b/src/main/kotlin/gui/config/storage/FirstLevelSplitJsonFolder.kt new file mode 100644 index 0000000..ff544d5 --- /dev/null +++ b/src/main/kotlin/gui/config/storage/FirstLevelSplitJsonFolder.kt @@ -0,0 +1,83 @@ +@file:OptIn(ExperimentalSerializationApi::class) + +package moe.nea.firmament.gui.config.storage + +import java.nio.file.Path +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.decodeFromStream +import kotlinx.serialization.json.encodeToStream +import kotlin.io.path.deleteExisting +import kotlin.io.path.inputStream +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.nameWithoutExtension +import kotlin.io.path.outputStream +import moe.nea.firmament.Firmament + +class FirstLevelSplitJsonFolder( + val context: ConfigLoadContext, + val folder: Path +) { + fun load(): JsonObject { + context.logInfo("Loading FLSJF from $folder") + return folder.listDirectoryEntries("*.json") + .mapNotNull(::loadIndividualFile) + .toMap() + .let(::JsonObject) + .also { context.logInfo("FLSJF from $folder - Voller Erfolg!") } + } + + fun loadIndividualFile(path: Path): Pair<String, JsonElement>? { + context.logInfo("Loading partial file from $path") + return try { + path.inputStream().use { + path.nameWithoutExtension to Firmament.json.decodeFromStream(JsonElement.serializer(), it) + } + } catch (ex: Exception) { + context.logError("Could not load file from $path", ex) + null + } + } + + fun save(value: JsonObject) { + context.logInfo("Saving FLSJF to $folder") + context.logDebug("Current value:\n$value") + val entries = folder.listDirectoryEntries("*.json") + .toMutableList() + for ((name, element) in value) { + val path = saveIndividualFile(name, element) + if (path != null) { + entries.remove(path) + } + } + if (entries.isNotEmpty()) { + context.logInfo("Deleting additional files.") + for (path in entries) { + context.logInfo("Deleting $path") +// context.backup(path) + try { + path.deleteExisting() + } catch (ex: Exception) { + context.logError("Could not delete $path", ex) + } + } + } + context.logInfo("FLSJF to $folder - Voller Erfolg!") + } + + fun saveIndividualFile(name: String, element: JsonElement): Path? { + try { + context.logInfo("Saving partial file with name $name") + val path = folder.resolve("$name.json") + context.ensureWritable(path) + path.outputStream().use { + Firmament.json.encodeToStream(JsonElement.serializer(), element, it) + } + return path + } catch (ex: Exception) { + context.logError("Could not save $name with value $element", ex) + return null + } + } +} diff --git a/src/main/kotlin/gui/config/storage/LegacyImporter.kt b/src/main/kotlin/gui/config/storage/LegacyImporter.kt new file mode 100644 index 0000000..8915c17 --- /dev/null +++ b/src/main/kotlin/gui/config/storage/LegacyImporter.kt @@ -0,0 +1,63 @@ +package moe.nea.firmament.gui.config.storage + +import java.nio.file.Path +import javax.xml.namespace.QName +import kotlin.io.path.Path +import kotlin.io.path.copyTo +import kotlin.io.path.copyToRecursively +import kotlin.io.path.createDirectories +import kotlin.io.path.createParentDirectories +import kotlin.io.path.exists +import kotlin.io.path.forEachDirectoryEntry +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.moveTo +import kotlin.io.path.name +import kotlin.io.path.nameWithoutExtension +import kotlin.io.path.writeText +import moe.nea.firmament.gui.config.storage.FirmamentConfigLoader.configFolder +import moe.nea.firmament.gui.config.storage.FirmamentConfigLoader.configVersionFile +import moe.nea.firmament.gui.config.storage.FirmamentConfigLoader.storageFolder + +object LegacyImporter { + val legacyConfigVersion = 995 + val backupPath = configFolder.resolveSibling("firmament-legacy-config-${System.currentTimeMillis()}") + + fun copyIf(from: Path, to: Path) { + if (from.exists()) { + to.createParentDirectories() + from.copyTo(to) + } + } + + fun importFromLegacy() { + configFolder.moveTo(backupPath) + configFolder.createDirectories() + + copyIf( + backupPath.resolve("inventory-buttons.json"), + storageFolder.resolve("inventory-buttons.json") + ) + + backupPath.listDirectoryEntries("*.json") + .forEach { path -> + val name = path.name + if (name == "inventory-buttons.json") + return@forEach + path.copyTo(configFolder.resolve(name)) + } + + backupPath.resolve("profiles") + .forEachDirectoryEntry { category -> + category.forEachDirectoryEntry { profile -> + copyIf( + profile, + FirmamentConfigLoader.profilePath + .resolve(profile.nameWithoutExtension) + .resolve(category.name + ".json") + ) + } + } + + configVersionFile.writeText(legacyConfigVersion.toString()) + } +} diff --git a/src/main/kotlin/jarvis/JarvisIntegration.kt b/src/main/kotlin/jarvis/JarvisIntegration.kt index 96f47f7..0dc75e4 100644 --- a/src/main/kotlin/jarvis/JarvisIntegration.kt +++ b/src/main/kotlin/jarvis/JarvisIntegration.kt @@ -39,7 +39,7 @@ class JarvisIntegration : JarvisPlugin { } override fun onHudEditorClosed() { - configs.forEach { it.save() } + configs.forEach { it.markDirty() } } override fun getAllConfigOptions(): List<JarvisConfigOption> { diff --git a/src/main/kotlin/repo/RepoManager.kt b/src/main/kotlin/repo/RepoManager.kt index c3d1c52..d25494f 100644 --- a/src/main/kotlin/repo/RepoManager.kt +++ b/src/main/kotlin/repo/RepoManager.kt @@ -17,7 +17,7 @@ import net.minecraft.util.StringIdentifiable import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament.logger import moe.nea.firmament.events.ReloadRegistrationEvent -import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.ErrorUtil import moe.nea.firmament.util.MC import moe.nea.firmament.util.MinecraftDispatcher @@ -35,18 +35,18 @@ object RepoManager { username = "NotEnoughUpdates" reponame = "NotEnoughUpdates-REPO" branch = "master" - save() + markDirty() } val enableREI by toggle("enable-rei") { true } val disableItemGroups by toggle("disable-item-groups") { true } val reload by button("reload") { - save() + markDirty() Firmament.coroutineScope.launch { RepoManager.reload() } } val redownload by button("redownload") { - save() + markDirty() RepoManager.launchAsyncUpdate(true) } val alwaysSuperCraft by toggle("enable-super-craft") { true } diff --git a/src/main/kotlin/util/SBData.kt b/src/main/kotlin/util/SBData.kt index 1a4734c..8675842 100644 --- a/src/main/kotlin/util/SBData.kt +++ b/src/main/kotlin/util/SBData.kt @@ -18,6 +18,10 @@ object SBData { "CLICK THIS TO SUGGEST IT IN CHAT [DASHES]", "CLICK THIS TO SUGGEST IT IN CHAT [NO DASHES]", ) + + val NULL_UUID = UUID(0L, 0L) + val profileIdOrNil get() = profileId ?: NULL_UUID + var profileId: UUID? = null get() { // TODO: allow unfiltered access to this somehow diff --git a/src/main/kotlin/util/data/Config.kt b/src/main/kotlin/util/data/Config.kt new file mode 100644 index 0000000..41de039 --- /dev/null +++ b/src/main/kotlin/util/data/Config.kt @@ -0,0 +1,15 @@ +package moe.nea.firmament.util.data + +import moe.nea.firmament.util.compatloader.CompatLoader + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS) +annotation class Config(val prefix: String = "") + + +interface IConfigProvider { + val configs: List<IDataHolder<*>> + companion object { + val providers = CompatLoader(IConfigProvider::class) + } +} diff --git a/src/main/kotlin/util/data/DataHolder.kt b/src/main/kotlin/util/data/DataHolder.kt index 21a6014..9f21125 100644 --- a/src/main/kotlin/util/data/DataHolder.kt +++ b/src/main/kotlin/util/data/DataHolder.kt @@ -1,5 +1,3 @@ - - package moe.nea.firmament.util.data import java.nio.file.Path @@ -8,55 +6,13 @@ import kotlin.io.path.exists import kotlin.io.path.readText import kotlin.io.path.writeText import moe.nea.firmament.Firmament +import moe.nea.firmament.gui.config.storage.ConfigStorageClass abstract class DataHolder<T>( - val serializer: KSerializer<T>, - val name: String, - val default: () -> T -) : IDataHolder<T> { - - - final override var data: T - private set - - init { - data = readValueOrDefault() - IDataHolder.putDataHolder(this::class, this) - } - - private val file: Path get() = Firmament.CONFIG_DIR.resolve("$name.json") - - protected fun readValueOrDefault(): T { - if (file.exists()) - try { - return Firmament.json.decodeFromString( - serializer, - file.readText() - ) - } catch (e: Exception) {/* Expecting IOException and SerializationException, but Kotlin doesn't allow multi catches*/ - IDataHolder.badLoads.add(name) - Firmament.logger.error( - "Exception during loading of config file $name. This will reset this config.", - e - ) - } - return default() - } - - private fun writeValue(t: T) { - file.writeText(Firmament.json.encodeToString(serializer, t)) - } - - override fun save() { - writeValue(data) - } - - override fun load() { - data = readValueOrDefault() - } - - override fun markDirty() { - IDataHolder.markDirty(this::class) - } - + serializer: KSerializer<T>, + name: String, + default: () -> T +) : GenericConfig<T>(name, serializer, default) { + override val storageClass: ConfigStorageClass + get() = ConfigStorageClass.STORAGE } diff --git a/src/main/kotlin/util/data/IDataHolder.kt b/src/main/kotlin/util/data/IDataHolder.kt index 1e9ba98..81198ee 100644 --- a/src/main/kotlin/util/data/IDataHolder.kt +++ b/src/main/kotlin/util/data/IDataHolder.kt @@ -1,71 +1,95 @@ package moe.nea.firmament.util.data -import java.util.concurrent.CopyOnWriteArrayList -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents -import kotlin.reflect.KClass -import net.minecraft.text.Text +import java.util.UUID +import kotlinx.serialization.KSerializer +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.buildJsonObject import moe.nea.firmament.Firmament -import moe.nea.firmament.events.ScreenChangeEvent -import moe.nea.firmament.util.MC +import moe.nea.firmament.gui.config.storage.ConfigStorageClass +import moe.nea.firmament.gui.config.storage.FirmamentConfigLoader +import moe.nea.firmament.util.SBData -interface IDataHolder<T> { - companion object { - internal var badLoads: MutableList<String> = CopyOnWriteArrayList() - private val allConfigs: MutableMap<KClass<out IDataHolder<*>>, IDataHolder<*>> = mutableMapOf() - private val dirty: MutableSet<KClass<out IDataHolder<*>>> = mutableSetOf() +sealed interface IDataHolder<T> { + fun markDirty() { + FirmamentConfigLoader.markDirty(this) + } - internal fun <T : IDataHolder<K>, K> putDataHolder(kClass: KClass<T>, inst: IDataHolder<K>) { - allConfigs[kClass] = inst - } + fun keys(): Collection<T> + fun saveTo(key: T): JsonObject + fun loadFrom(key: T, jsonObject: JsonObject) + fun clear() + val storageClass: ConfigStorageClass +} - fun <T : IDataHolder<K>, K> markDirty(kClass: KClass<T>) { - if (kClass !in allConfigs) { - Firmament.logger.error("Tried to markDirty '${kClass.qualifiedName}', which isn't registered as 'IConfigHolder'") - return - } - dirty.add(kClass) - } +open class ProfileKeyedConfig<T>( + val prefix: String, + val serializer: KSerializer<T>, + val default: () -> T, +) : IDataHolder<UUID> { - private fun performSaves() { - val toSave = dirty.toList().also { - dirty.clear() - } - for (it in toSave) { - val obj = allConfigs[it] - if (obj == null) { - Firmament.logger.error("Tried to save '${it}', which isn't registered as 'ConfigHolder'") - continue - } - obj.save() - } - } + override val storageClass: ConfigStorageClass + get() = ConfigStorageClass.PROFILE + private var _data: MutableMap<UUID, T>? = null + + val data + get() = _data!!.let { map -> + map[SBData.profileIdOrNil] + ?: default().also { map[SBData.profileIdOrNil] = it } + } ?: error("Config $this not loaded — forgot to register?") - private fun warnForResetConfigs() { - if (badLoads.isNotEmpty()) { - MC.sendChat( - Text.literal( - "The following configs have been reset: ${badLoads.joinToString(", ")}. " + - "This can be intentional, but probably isn't." - ) - ) - badLoads.clear() - } + override fun keys(): Collection<UUID> { + return _data!!.keys + } + + override fun saveTo(key: UUID): JsonObject { + val d = _data!! + return buildJsonObject { + put(prefix, Firmament.json.encodeToJsonElement(serializer, d[key] ?: return@buildJsonObject)) } + } - fun registerEvents() { - ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event -> - performSaves() - warnForResetConfigs() - } - ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping { - performSaves() - }) + override fun loadFrom(key: UUID, jsonObject: JsonObject) { + (_data ?: mutableMapOf<UUID, T>().also { _data = it })[key] = + jsonObject[prefix] + ?.let { + Firmament.json.decodeFromJsonElement(serializer, it) + } ?: default() + } + + override fun clear() { + _data = null + } +} + +abstract class GenericConfig<T>( + val prefix: String, + val serializer: KSerializer<T>, + val default: () -> T, +) : IDataHolder<Unit> { + + private var _data: T? = null + + val data get() = _data ?: error("Config $this not loaded — forgot to register?") + + override fun keys(): Collection<Unit> { + return listOf(Unit) + } + + open fun onLoad() { + } + + override fun saveTo(key: Unit): JsonObject { + return buildJsonObject { + put(prefix, Firmament.json.encodeToJsonElement(serializer, data)) } + } + override fun loadFrom(key: Unit, jsonObject: JsonObject) { + _data = jsonObject[prefix]?.let { Firmament.json.decodeFromJsonElement(serializer, it) } ?: default() + onLoad() } - val data: T - fun save() - fun markDirty() - fun load() + override fun clear() { + _data = null + } } diff --git a/src/main/kotlin/util/data/MultiFileDataHolder.kt b/src/main/kotlin/util/data/MultiFileDataHolder.kt index 94c6f05..209f780 100644 --- a/src/main/kotlin/util/data/MultiFileDataHolder.kt +++ b/src/main/kotlin/util/data/MultiFileDataHolder.kt @@ -28,7 +28,6 @@ abstract class MultiFileDataHolder<T>( try { it.nameWithoutExtension to Firmament.json.decodeFromString(dataSerializer, it.readText()) } catch (e: Exception) { /* Expecting IOException and SerializationException, but Kotlin doesn't allow multi catches*/ - IDataHolder.badLoads.add(configName) Firmament.logger.error( "Exception during loading of multi file data holder $it ($configName). This will reset that profiles config.", e diff --git a/src/main/kotlin/util/data/ProfileSpecificDataHolder.kt b/src/main/kotlin/util/data/ProfileSpecificDataHolder.kt index 1cd4f22..3922c34 100644 --- a/src/main/kotlin/util/data/ProfileSpecificDataHolder.kt +++ b/src/main/kotlin/util/data/ProfileSpecificDataHolder.kt @@ -1,84 +1,9 @@ - - package moe.nea.firmament.util.data -import java.nio.file.Path -import java.util.UUID import kotlinx.serialization.KSerializer -import kotlin.io.path.createDirectories -import kotlin.io.path.deleteExisting -import kotlin.io.path.exists -import kotlin.io.path.extension -import kotlin.io.path.listDirectoryEntries -import kotlin.io.path.nameWithoutExtension -import kotlin.io.path.readText -import kotlin.io.path.writeText -import moe.nea.firmament.Firmament -import moe.nea.firmament.util.SBData abstract class ProfileSpecificDataHolder<S>( - private val dataSerializer: KSerializer<S>, - val configName: String, - private val configDefault: () -> S -) : IDataHolder<S?> { - - var allConfigs: MutableMap<UUID, S> - - override val data: S? - get() = SBData.profileId?.let { - allConfigs.computeIfAbsent(it) { configDefault() } - } - - init { - allConfigs = readValues() - IDataHolder.putDataHolder(this::class, this) - } - - private val configDirectory: Path get() = Firmament.CONFIG_DIR.resolve("profiles").resolve(configName) - - private fun readValues(): MutableMap<UUID, S> { - if (!configDirectory.exists()) { - configDirectory.createDirectories() - } - val profileFiles = configDirectory.listDirectoryEntries() - return profileFiles - .filter { it.extension == "json" } - .mapNotNull { - try { - UUID.fromString(it.nameWithoutExtension) to Firmament.json.decodeFromString(dataSerializer, it.readText()) - } catch (e: Exception) { /* Expecting IOException and SerializationException, but Kotlin doesn't allow multi catches*/ - IDataHolder.badLoads.add(configName) - Firmament.logger.error( - "Exception during loading of profile specific config file $it ($configName). This will reset that profiles config.", - e - ) - null - } - }.toMap().toMutableMap() - } - - override fun save() { - if (!configDirectory.exists()) { - configDirectory.createDirectories() - } - val c = allConfigs - configDirectory.listDirectoryEntries().forEach { - if (it.nameWithoutExtension !in c.mapKeys { it.toString() }) { - it.deleteExisting() - } - } - c.forEach { (name, value) -> - val f = configDirectory.resolve("$name.json") - f.writeText(Firmament.json.encodeToString(dataSerializer, value)) - } - } - - override fun markDirty() { - IDataHolder.markDirty(this::class) - } - - override fun load() { - allConfigs = readValues() - } - -} + dataSerializer: KSerializer<S>, + configName: String, + configDefault: () -> S +) : ProfileKeyedConfig<S>(configName, dataSerializer, configDefault) diff --git a/src/main/kotlin/util/json/jsonConversion.kt b/src/main/kotlin/util/json/jsonConversion.kt new file mode 100644 index 0000000..899ae11 --- /dev/null +++ b/src/main/kotlin/util/json/jsonConversion.kt @@ -0,0 +1,66 @@ +package moe.nea.firmament.util.json + +import com.google.gson.JsonArray +import com.google.gson.JsonElement +import com.google.gson.JsonNull +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import com.google.gson.internal.LazilyParsedNumber +import kotlin.collections.map + + +fun JsonElement.intoKotlinJson(): kotlinx.serialization.json.JsonElement { + when (this) { + is JsonNull -> return kotlinx.serialization.json.JsonNull + is JsonObject -> { + return kotlinx.serialization.json.JsonObject( + this.entrySet() + .associate { it.key to it.value.intoKotlinJson() }) + } + + is JsonArray -> { + return kotlinx.serialization.json.JsonArray(this.map { it.intoKotlinJson() }) + } + + is JsonPrimitive -> { + if (this.isString) + return kotlinx.serialization.json.JsonPrimitive(this.asString) + if (this.isBoolean) + return kotlinx.serialization.json.JsonPrimitive(this.asBoolean) + return kotlinx.serialization.json.JsonPrimitive(this.asNumber) + } + + else -> error("Unknown json variant $this") + } +} + +fun kotlinx.serialization.json.JsonElement.intoGson(): JsonElement { + when (this) { + is kotlinx.serialization.json.JsonNull -> return JsonNull.INSTANCE + is kotlinx.serialization.json.JsonPrimitive -> { + if (this.isString) + return JsonPrimitive(this.content) + if (this.content == "true") + return JsonPrimitive(true) + if (this.content == "false") + return JsonPrimitive(false) + return JsonPrimitive(LazilyParsedNumber(this.content)) + } + + is kotlinx.serialization.json.JsonObject -> { + val obj = JsonObject() + for ((k, v) in this) { + obj.add(k, v.intoGson()) + } + return obj + } + + is kotlinx.serialization.json.JsonArray -> { + val arr = JsonArray() + for (v in this) { + arr.add(v.intoGson()) + } + return arr + } + } +} diff --git a/src/main/kotlin/util/skyblock/SackUtil.kt b/src/main/kotlin/util/skyblock/SackUtil.kt index c46542e..8c82022 100644 --- a/src/main/kotlin/util/skyblock/SackUtil.kt +++ b/src/main/kotlin/util/skyblock/SackUtil.kt @@ -8,6 +8,8 @@ import net.minecraft.text.Text import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ChestInventoryUpdateEvent import moe.nea.firmament.events.ProcessChatEvent +import moe.nea.firmament.gui.config.storage.ConfigFixEvent +import moe.nea.firmament.gui.config.storage.ConfigStorageClass import moe.nea.firmament.repo.ItemNameLookup import moe.nea.firmament.util.SHORT_NUMBER_FORMAT import moe.nea.firmament.util.SkyblockId @@ -28,7 +30,14 @@ object SackUtil { // val sackTypes: ) - object Store : ProfileSpecificDataHolder<SackContents>(serializer(), "Sacks", ::SackContents) + object Store : ProfileSpecificDataHolder<SackContents>(serializer(), "sacks", ::SackContents) + + @Subscribe + fun onConfigFix(event: ConfigFixEvent) { + event.on(996, ConfigStorageClass.PROFILE) { + move("Sacks", "sacks") + } + } val items get() = Store.data?.contents ?: mutableMapOf() val storedRegex = "^Stored: (?<stored>$SHORT_NUMBER_FORMAT)/(?<max>$SHORT_NUMBER_FORMAT)$".toPattern() |
