aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/firmament/util/data/ProfileSpecificDataHolder.kt
blob: 06523c303d18417ae3c2573a7f9f2ee611838c77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
 * Firmament is a Hypixel Skyblock mod for modern Minecraft versions
 * Copyright (C) 2023 Linnea Gräf
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

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()
        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()
    }

}