diff options
Diffstat (limited to 'src/main/kotlin/util/data')
| -rw-r--r-- | src/main/kotlin/util/data/Config.kt | 15 | ||||
| -rw-r--r-- | src/main/kotlin/util/data/DataHolder.kt | 63 | ||||
| -rw-r--r-- | src/main/kotlin/util/data/IDataHolder.kt | 154 | ||||
| -rw-r--r-- | src/main/kotlin/util/data/ProfileSpecificDataHolder.kt | 83 |
4 files changed, 126 insertions, 189 deletions
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..c138d78 100644 --- a/src/main/kotlin/util/data/DataHolder.kt +++ b/src/main/kotlin/util/data/DataHolder.kt @@ -1,62 +1,13 @@ - - package moe.nea.firmament.util.data -import java.nio.file.Path import kotlinx.serialization.KSerializer -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..3229011 100644 --- a/src/main/kotlin/util/data/IDataHolder.kt +++ b/src/main/kotlin/util/data/IDataHolder.kt @@ -1,71 +1,117 @@ 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 java.util.concurrent.CompletableFuture +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 class IDataHolder<T> { + fun markDirty(future: CompletableFuture<Void?>? = null) { + FirmamentConfigLoader.markDirty(this, future) + } - internal fun <T : IDataHolder<K>, K> putDataHolder(kClass: KClass<T>, inst: IDataHolder<K>) { - allConfigs[kClass] = inst - } + init { + require(this.javaClass.getAnnotation(Config::class.java) != null) + } + + abstract fun keys(): Collection<T> + abstract fun saveTo(key: T): JsonObject + abstract fun loadFrom(key: T, jsonObject: JsonObject) + abstract fun explicitDefaultLoad() + abstract fun clear() + abstract val storageClass: ConfigStorageClass +} + +open class ProfileKeyedConfig<T>( + val prefix: String, + val serializer: KSerializer<T>, + val default: () -> T & Any, +) : IDataHolder<UUID>() { + + override val storageClass: ConfigStorageClass + get() = ConfigStorageClass.PROFILE + private var _data: MutableMap<UUID, T>? = null - 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) + val data: T & Any + get() { + val map = _data ?: error("Config $this not loaded — forgot to register?") + map[SBData.profileIdOrNil]?.let { return it } + val newValue = default() + map[SBData.profileIdOrNil] = newValue + return newValue } - 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 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)) } + } - 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 loadFrom(key: UUID, jsonObject: JsonObject) { + var map = _data + if (map == null) { + map = mutableMapOf() + _data = map } + map[key] = + jsonObject[prefix] + ?.let { + Firmament.json.decodeFromJsonElement(serializer, it) + } ?: default() + } - fun registerEvents() { - ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event -> - performSaves() - warnForResetConfigs() - } - ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping { - performSaves() - }) + override fun explicitDefaultLoad() { + _data = mutableMapOf() + } + + 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) + } + + override fun explicitDefaultLoad() { + _data = default() + } + + 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/ProfileSpecificDataHolder.kt b/src/main/kotlin/util/data/ProfileSpecificDataHolder.kt index 1cd4f22..853ba7d 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 & Any +) : ProfileKeyedConfig<S>(configName, dataSerializer, configDefault) |
