From e8c5e9490293adb07656f3ad7121f483f04bc8f0 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Wed, 1 Dec 2021 22:51:46 +0100 Subject: [PATCH] config option listening --- .../bixilon/minosoft/config/config/Config.kt | 2 - .../minosoft/config/config/eros/ErosConfig.kt | 21 ------- .../config/profile/GlobalProfileManager.kt | 9 +++ .../minosoft/config/profile/ProfileManager.kt | 8 ++- .../profile/change/ProfilesChangeManager.kt | 59 +++++++++++++++++++ .../change/listener/ProfileChangeListener.kt | 14 +++++ .../listener/SimpleProfileChangeListener.kt | 31 ++++++++++ .../profile/profiles/eros/ErosProfile.kt | 2 + .../profiles/eros/ErosProfileManager.kt | 1 + .../profile/profiles/eros/server/ServerC.kt | 7 +++ .../profiles/eros/server/modify/ModifyC.kt | 8 +++ .../config/profile/util/ProfileDelegate.kt | 23 ++++++-- .../gui/eros/dialog/UpdateServerDialog.kt | 17 ++++-- 13 files changed, 164 insertions(+), 38 deletions(-) delete mode 100644 src/main/java/de/bixilon/minosoft/config/config/eros/ErosConfig.kt create mode 100644 src/main/java/de/bixilon/minosoft/config/profile/change/ProfilesChangeManager.kt create mode 100644 src/main/java/de/bixilon/minosoft/config/profile/change/listener/ProfileChangeListener.kt create mode 100644 src/main/java/de/bixilon/minosoft/config/profile/change/listener/SimpleProfileChangeListener.kt create mode 100644 src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/ServerC.kt create mode 100644 src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/modify/ModifyC.kt diff --git a/src/main/java/de/bixilon/minosoft/config/config/Config.kt b/src/main/java/de/bixilon/minosoft/config/config/Config.kt index 5979917d9..711969ac1 100644 --- a/src/main/java/de/bixilon/minosoft/config/config/Config.kt +++ b/src/main/java/de/bixilon/minosoft/config/config/Config.kt @@ -17,7 +17,6 @@ import de.bixilon.minosoft.config.config.account.AccountConfig import de.bixilon.minosoft.config.config.chat.ChatConfig import de.bixilon.minosoft.config.config.debug.DebugConfig import de.bixilon.minosoft.config.config.download.DownloadConfig -import de.bixilon.minosoft.config.config.eros.ErosConfig import de.bixilon.minosoft.config.config.game.GameConfig import de.bixilon.minosoft.config.config.general.GeneralConfig import de.bixilon.minosoft.config.config.network.NetworkConfig @@ -32,5 +31,4 @@ data class Config( val server: ServerConfig = ServerConfig(), val download: DownloadConfig = DownloadConfig(), val debug: DebugConfig = DebugConfig(), - val eros: ErosConfig = ErosConfig(), ) diff --git a/src/main/java/de/bixilon/minosoft/config/config/eros/ErosConfig.kt b/src/main/java/de/bixilon/minosoft/config/config/eros/ErosConfig.kt deleted file mode 100644 index 7b6d68e76..000000000 --- a/src/main/java/de/bixilon/minosoft/config/config/eros/ErosConfig.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Minosoft - * Copyright (C) 2021 Moritz Zwerger - * - * 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 . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.config.config.eros - -import com.squareup.moshi.Json - -data class ErosConfig( - @Json(name = "show_releases") var showReleases: Boolean = true, - @Json(name = "show_snapshots") var showSnapshots: Boolean = false, -) diff --git a/src/main/java/de/bixilon/minosoft/config/profile/GlobalProfileManager.kt b/src/main/java/de/bixilon/minosoft/config/profile/GlobalProfileManager.kt index 9bfeb26d5..f6361d3ac 100644 --- a/src/main/java/de/bixilon/minosoft/config/profile/GlobalProfileManager.kt +++ b/src/main/java/de/bixilon/minosoft/config/profile/GlobalProfileManager.kt @@ -22,6 +22,15 @@ object GlobalProfileManager { ErosProfileManager, ) private val SELECTED_PROFILES_TYPE: MapType = Jackson.MAPPER.typeFactory.constructMapType(HashMap::class.java, ResourceLocation::class.java, String::class.java) + val CLASS_MAPPING: Map, ProfileManager<*>> + + init { + val classMapping: MutableMap, ProfileManager<*>> = mutableMapOf() + for (manager in DEFAULT_MANAGERS) { + classMapping[manager.profileClass] = manager + } + CLASS_MAPPING = classMapping.toMap() + } private var initialized = false private var loading = true diff --git a/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt b/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt index fb728895c..a4bbffd8c 100644 --- a/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt +++ b/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt @@ -24,6 +24,7 @@ interface ProfileManager { val namespace: ResourceLocation val latestVersion: Int val saveLock: ReentrantLock + val profileClass: Class val profiles: HashBiMap var selected: T @@ -93,7 +94,7 @@ interface ProfileManager { if (selected == null || profileNames.isEmpty()) { initDefaultProfile() } - var migrated = false + var saveFile = false for (profileName in profileNames) { val path = getPath(profileName, baseDirectory) val json: MutableMap? @@ -110,14 +111,15 @@ interface ProfileManager { } Log.log(LogMessageType.LOAD_PROFILES, LogLevels.INFO) { "Migrated profile ($path) from version $version to $latestVersion" } json["version"] = latestVersion - migrated = true + saveFile = true } } else { json = null + saveFile = true } val profile = load(profileName, json) - if (migrated) { + if (saveFile) { profile.saved = false save(profile) } diff --git a/src/main/java/de/bixilon/minosoft/config/profile/change/ProfilesChangeManager.kt b/src/main/java/de/bixilon/minosoft/config/profile/change/ProfilesChangeManager.kt new file mode 100644 index 000000000..cf3befdd1 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/config/profile/change/ProfilesChangeManager.kt @@ -0,0 +1,59 @@ +package de.bixilon.minosoft.config.profile.change + +import de.bixilon.minosoft.config.profile.GlobalProfileManager +import de.bixilon.minosoft.config.profile.change.listener.ProfileChangeListener +import de.bixilon.minosoft.config.profile.profiles.Profile +import de.bixilon.minosoft.util.KUtil.synchronizedMapOf +import de.bixilon.minosoft.util.KUtil.synchronizedSetOf +import de.bixilon.minosoft.util.KUtil.toSynchronizedSet +import de.bixilon.minosoft.util.KUtil.unsafeCast +import de.bixilon.minosoft.util.collections.SynchronizedMap +import java.lang.ref.WeakReference +import java.lang.reflect.Field + +object ProfilesChangeManager { + private val listeners: SynchronizedMap, ProfileChangeListener>>>> = synchronizedMapOf() + + fun register(reference: Any, listener: ProfileChangeListener) { + this.listeners.getOrPut(listener.field) { synchronizedMapOf() }.getOrPut(listener.profile) { synchronizedSetOf() }.add(Pair(WeakReference(reference), listener.unsafeCast())) + } + + fun onChange(profile: Profile, field: Field, previous: Any?, value: Any?) { + val fieldListeners = listeners[field] ?: return + + fun work(queue: MutableSet, ProfileChangeListener>>) { + val toRemove: MutableSet, ProfileChangeListener>> = mutableSetOf() + for (pair in queue.toSynchronizedSet()) { + val (reference, listener) = pair + if (reference.get() == null) { + toRemove += pair + } + listener.invoke(previous.unsafeCast(), value.unsafeCast()) + } + if (toRemove.isNotEmpty()) { + if (queue.size == toRemove.size) { + queue.clear() + } else { + queue.removeAll(toRemove) + } + } + } + + fieldListeners[profile]?.let { + work(it) + if (it.isEmpty()) { + fieldListeners -= profile + } + } + + val manager = GlobalProfileManager.CLASS_MAPPING[profile::class.java] ?: return + if (profile == manager.selected) { + fieldListeners[null]?.let { + work(it) + if (it.isEmpty()) { + fieldListeners -= null + } + } + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/config/profile/change/listener/ProfileChangeListener.kt b/src/main/java/de/bixilon/minosoft/config/profile/change/listener/ProfileChangeListener.kt new file mode 100644 index 000000000..b83bab2f7 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/config/profile/change/listener/ProfileChangeListener.kt @@ -0,0 +1,14 @@ +package de.bixilon.minosoft.config.profile.change.listener + +import de.bixilon.minosoft.config.profile.profiles.Profile +import java.lang.reflect.Field +import kotlin.reflect.KProperty + +interface ProfileChangeListener { + val property: KProperty + val field: Field + val profile: Profile? + + + fun invoke(previous: T, value: T) +} diff --git a/src/main/java/de/bixilon/minosoft/config/profile/change/listener/SimpleProfileChangeListener.kt b/src/main/java/de/bixilon/minosoft/config/profile/change/listener/SimpleProfileChangeListener.kt new file mode 100644 index 000000000..a5a36ffcf --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/config/profile/change/listener/SimpleProfileChangeListener.kt @@ -0,0 +1,31 @@ +package de.bixilon.minosoft.config.profile.change.listener + +import de.bixilon.minosoft.config.profile.change.ProfilesChangeManager +import de.bixilon.minosoft.config.profile.profiles.Profile +import de.bixilon.minosoft.gui.eros.util.JavaFXUtil +import java.lang.reflect.Field +import kotlin.reflect.KProperty +import kotlin.reflect.jvm.javaField + +class SimpleProfileChangeListener( + override val property: KProperty, + override val field: Field, + override val profile: Profile?, + private val callback: (T) -> Unit, +) : ProfileChangeListener { + + override fun invoke(previous: T, value: T) { + callback(value) + } + + companion object { + + fun KProperty.listen(reference: Any, profile: Profile? = null, callback: ((T) -> Unit)) { + ProfilesChangeManager.register(reference, SimpleProfileChangeListener(this, javaField!!, profile, callback)) + } + + fun KProperty.listenFX(reference: Any, profile: Profile? = null, callback: ((T) -> Unit)) { + ProfilesChangeManager.register(reference, SimpleProfileChangeListener(this, javaField!!, profile) { JavaFXUtil.runLater { callback(it) } }) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/ErosProfile.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/ErosProfile.kt index 966d05676..afcb9211d 100644 --- a/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/ErosProfile.kt +++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/ErosProfile.kt @@ -4,6 +4,7 @@ import de.bixilon.minosoft.config.profile.profiles.Profile import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager.delegate import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager.latestVersion import de.bixilon.minosoft.config.profile.profiles.eros.general.GeneralC +import de.bixilon.minosoft.config.profile.profiles.eros.server.ServerC class ErosProfile( description: String? = null, @@ -16,6 +17,7 @@ class ErosProfile( override var saved: Boolean = true val general: GeneralC = GeneralC() + val server: ServerC = ServerC() override fun toString(): String { return ErosProfileManager.getName(this) diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/ErosProfileManager.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/ErosProfileManager.kt index 78f086fa4..2a44ba3d3 100644 --- a/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/ErosProfileManager.kt +++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/ErosProfileManager.kt @@ -14,6 +14,7 @@ object ErosProfileManager : ProfileManager { override val namespace = "minosoft:eros".toResourceLocation() override val latestVersion = 1 override val saveLock = ReentrantLock() + override val profileClass = ErosProfile::class.java private var currentLoadingPath: String? = null diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/ServerC.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/ServerC.kt new file mode 100644 index 000000000..e7ff37a22 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/ServerC.kt @@ -0,0 +1,7 @@ +package de.bixilon.minosoft.config.profile.profiles.eros.server + +import de.bixilon.minosoft.config.profile.profiles.eros.server.modify.ModifyC + +class ServerC { + val modify = ModifyC() +} diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/modify/ModifyC.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/modify/ModifyC.kt new file mode 100644 index 000000000..7b85faf1b --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/modify/ModifyC.kt @@ -0,0 +1,8 @@ +package de.bixilon.minosoft.config.profile.profiles.eros.server.modify + +import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager.delegate + +class ModifyC { + var showReleases by delegate(true) + var showSnapshots by delegate(false) +} diff --git a/src/main/java/de/bixilon/minosoft/config/profile/util/ProfileDelegate.kt b/src/main/java/de/bixilon/minosoft/config/profile/util/ProfileDelegate.kt index 139744b2d..34205dc54 100644 --- a/src/main/java/de/bixilon/minosoft/config/profile/util/ProfileDelegate.kt +++ b/src/main/java/de/bixilon/minosoft/config/profile/util/ProfileDelegate.kt @@ -1,11 +1,14 @@ package de.bixilon.minosoft.config.profile.util import de.bixilon.minosoft.config.profile.ProfileManager +import de.bixilon.minosoft.config.profile.change.ProfilesChangeManager +import de.bixilon.minosoft.config.profile.profiles.Profile import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogMessageType import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty +import kotlin.reflect.jvm.javaField open class ProfileDelegate( private var value: V, @@ -13,7 +16,7 @@ open class ProfileDelegate( private val profileManager: ProfileManager<*>, private val profileName: String, ) : ReadWriteProperty { - + private lateinit var profile: Profile override fun getValue(thisRef: Any, property: KProperty<*>): V { return value @@ -23,16 +26,24 @@ open class ProfileDelegate( if (checkEquals && this.value == value) { return } - val profile = profileManager.profiles[profileName] - if (profile == null || profile.initializing) { + if (!this::profile.isInitialized) { + val profile = profileManager.profiles[profileName] + if (profile == null) { + this.value = value + return + } + this.profile = profile + } + if (profile.initializing) { this.value = value return } - Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Changed option $property in $thisRef in profile ${profileName::class.java} from ${this.value} to $value" } + Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Changed option $property in profile $profileName from ${this.value} to $value" } profileManager.profiles[profileName]?.saved = false - - // ToDo: Fire event + val previous = this.value this.value = value + + ProfilesChangeManager.onChange(profile, property.javaField ?: return, previous, value) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/dialog/UpdateServerDialog.kt b/src/main/java/de/bixilon/minosoft/gui/eros/dialog/UpdateServerDialog.kt index d1b3c70e4..fe7d59cc0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/dialog/UpdateServerDialog.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/dialog/UpdateServerDialog.kt @@ -14,6 +14,9 @@ package de.bixilon.minosoft.gui.eros.dialog import de.bixilon.minosoft.Minosoft +import de.bixilon.minosoft.config.profile.change.listener.SimpleProfileChangeListener.Companion.listenFX +import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager +import de.bixilon.minosoft.config.profile.profiles.eros.server.modify.ModifyC import de.bixilon.minosoft.config.server.Server import de.bixilon.minosoft.data.registries.versions.Version import de.bixilon.minosoft.data.registries.versions.VersionTypes @@ -106,22 +109,24 @@ class UpdateServerDialog( cancelButtonFX.ctext = TranslatableComponents.GENERAL_CANCEL + val modifyConfig = ErosProfileManager.selected.server.modify + + ModifyC::showReleases.listenFX(this) { showReleasesFX.isSelected = it } + ModifyC::showSnapshots.listenFX(this) { showSnapshotsFX.isSelected = it } showReleasesFX.apply { - isSelected = Minosoft.config.config.eros.showReleases + isSelected = modifyConfig.showReleases ctext = SHOW_RELEASES setOnAction { - Minosoft.config.config.eros.showReleases = isSelected - Minosoft.config.saveToFile() + modifyConfig.showReleases = isSelected refreshVersions() } } showSnapshotsFX.apply { - isSelected = Minosoft.config.config.eros.showSnapshots + isSelected = modifyConfig.showSnapshots ctext = SHOW_SNAPSHOTS setOnAction { - Minosoft.config.config.eros.showSnapshots = isSelected - Minosoft.config.saveToFile() + modifyConfig.showSnapshots = isSelected refreshVersions() } }