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 | 58 | ||||
| -rw-r--r-- | src/main/kotlin/util/data/IDataHolder.kt | 136 | ||||
| -rw-r--r-- | src/main/kotlin/util/data/MultiFileDataHolder.kt | 1 | ||||
| -rw-r--r-- | src/main/kotlin/util/data/ProfileSpecificDataHolder.kt | 83 |
5 files changed, 106 insertions, 187 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..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) |
