SnowyGUI/common/src/main/kotlin/fr/username404/snowygui/config/Configuration.kt

139 lines
5.3 KiB
Kotlin

package fr.username404.snowygui.config
import com.typesafe.config.Config
import com.typesafe.config.ConfigException
import com.typesafe.config.ConfigFactory.empty
import com.typesafe.config.ConfigFactory.parseFile
import com.typesafe.config.ConfigFactory.load
import com.typesafe.config.ConfigFactory.parseString
import com.typesafe.config.ConfigRenderOptions
import com.typesafe.config.ConfigValueFactory
import fr.username404.snowygui.ClickGui
import fr.username404.snowygui.Snowy
import fr.username404.snowygui.Snowy.Companion.MissingComponent
import fr.username404.snowygui.gui.elements.ClickBox
import fr.username404.snowygui.gui.feature.Category
import fr.username404.snowygui.gui.feature.Macro
import io.github.config4k.extract
import io.github.config4k.getValue
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import net.minecraft.client.Minecraft
import java.io.File
import kotlin.reflect.KProperty
object Configuration {
@Deprecated("Use the getValue or setValue methods instead", level = DeprecationLevel.ERROR)
@JvmStatic
val ModifiableValues: MutableMap<String, Any?> by lazy {
mutableMapOf(
"enabledFeatures" to enabledFeatures,
"macros" to lazy {
(ClickGui.components.find { it is ClickBox && it.isCategory(Category.MACROS) } as ClickBox).buttons.map {
Json.encodeToString(it as Macro)
}
},
"box_colors" to mapOf<String, Int>(*ClickGui.clickBoxes.filter { box ->
(box.name.key != MissingComponent.key) && Category.fromBox(box)?.categoryColor != box.color
}.map {
it.name.key to it.color
}.toTypedArray()),
)
}
private fun Config.withFullModifiableValues() = @Suppress("DEPRECATION_ERROR")
ModifiableValues.entries.fold(this) { previous, entry ->
previous.withValue(entry.key, entry.value.let {
ConfigValueFactory.fromAnyRef(
if (it !is Lazy<*>) ConfigValueFactory.fromAnyRef(it) else it.value
)
}
)
}
private val configDirectory: String = (Minecraft.getInstance().gameDirectory.absolutePath + File.separator + "config").also { File(it).mkdir() }
private val file: File = File(configDirectory + File.separator + "snowy.conf")
private suspend fun writeConfig(c: Config) = coroutineScope {
launch(start = CoroutineStart.UNDISPATCHED) {
file.writeText(
"""
|Snowy {
|${
c.root().render(
ConfigRenderOptions.defaults()
.setFormatted(true)
.setJson(false)
.setOriginComments(false)
).prependIndent(" ").trimEnd()
}
|}
""".trimMargin()
)
}
}
operator fun invoke() = obtained
inline operator fun <reified T> getValue(ref: Any?, property: KProperty<*>): T = @Suppress("DEPRECATION_ERROR")
if (ModifiableValues.containsKey(property.name)) ModifiableValues[property.name] as T else invoke().getValue(ref, property)
operator fun <T> setValue(ref: Any?, property: KProperty<*>, value: T) = @Suppress("DEPRECATION_ERROR")
ModifiableValues.setValue(ref, property, value)
private val obtained: Config = run {
var result: Config = empty()
with(file) {
if (!exists()) {
createNewFile()
setWritable(true)
setReadable(true)
} else try {
result = parseFile(file)
} catch (e: ConfigException) {
Snowy.logs.warn("Could not parse the snowy configuration file, the default configuration will be used instead.")
}
}
load(result).withFallback(
parseString(
"""
|Snowy {
| displayInitMessage = false
| macros = []
| riskyCheats = false
| sortAlphabetically = true
|}
""".trimMargin()
)
).extract<Config>("Snowy")
}.also {
runBlocking {
writeConfig(it)
}
}
val enabledFeatures = mutableMapOf<String, Boolean>().apply {
"enabledFeatures".let { obtained.run {
if (hasPath(it)) { putAll(extract(it)) }
} }
}
internal val foundMacros: Set<Macro> = run {
obtained.getStringList("macros").map {
Json.decodeFromString<Macro>(it)
}.toSet()
}
init {
Runtime.getRuntime().addShutdownHook(
Thread {
runBlocking {
ClickGui.boxContext {
enabledFeatures.putAll(buttons.map {
it.title to it.toggled
})
}
writeConfig(obtained.withFullModifiableValues()).join()
}
}
)
}
}