diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/config/profile/delegate/types/RedirectDelegateTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/config/profile/delegate/types/RedirectDelegateTest.kt
new file mode 100644
index 000000000..fd6b08e8b
--- /dev/null
+++ b/src/integration-test/kotlin/de/bixilon/minosoft/config/profile/delegate/types/RedirectDelegateTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 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.profile.delegate.types
+
+import com.fasterxml.jackson.databind.InjectableValues
+import com.fasterxml.jackson.databind.node.ObjectNode
+import com.fasterxml.jackson.module.kotlin.convertValue
+import de.bixilon.kutil.concurrent.lock.Lock
+import de.bixilon.kutil.json.JsonObject
+import de.bixilon.minosoft.config.profile.ProfileLock
+import de.bixilon.minosoft.config.profile.profiles.Profile
+import de.bixilon.minosoft.config.profile.storage.ProfileStorage
+import de.bixilon.minosoft.util.json.Jackson
+import org.testng.Assert.assertEquals
+import org.testng.annotations.Test
+
+@Test(groups = ["profiles"])
+class RedirectDelegateTest {
+ private val jacksonType by lazy { Jackson.MAPPER.typeFactory.constructType(TestProfile::class.java) }
+ private val reader by lazy { Jackson.MAPPER.readerFor(jacksonType) }
+
+ private fun create(): TestProfile {
+ return TestProfile()
+ }
+
+ private fun TestProfile.update(data: JsonObject) {
+ val tree = Jackson.MAPPER.convertValue(data)
+
+
+ val injectable = InjectableValues.Std()
+ injectable.addValue(TestProfile::class.java, this)
+ reader
+ .withValueToUpdate(this)
+ .with(injectable)
+ .readValue(tree)
+ }
+
+ private fun TestProfile.serialize(): JsonObject {
+ return Jackson.MAPPER.convertValue(this, Jackson.JSON_MAP_TYPE)
+ }
+
+ fun setup() {
+ reader
+ val profile = create()
+ }
+
+ fun `update with just the normal property`() {
+ val profile = create()
+ assertEquals(profile.config.normal, "test")
+ profile.update(mapOf("config" to mapOf("normal" to "abc")))
+ assertEquals(profile.config.normal, "abc")
+ }
+
+ fun `update redirect property`() {
+ val profile = create()
+ assertEquals(profile.config.prop, null)
+ profile.update(mapOf("config" to mapOf("normal" to 12)))
+ assertEquals(profile.config.prop, Boxed(12, false))
+ }
+
+ fun `assign redirect property`() {
+ val profile = create()
+ profile.config.prop = Boxed(123, true)
+ }
+
+ fun `serialize redirect property`() {
+ val profile = create()
+ profile.config.prop = Boxed(123, true)
+ val data = profile.serialize()
+ assertEquals(data, mapOf("config" to mapOf("prop" to 123, "normal" to "test")))
+ }
+
+
+ class TestProfile(
+ override var storage: ProfileStorage? = null,
+ override val lock: Lock = ProfileLock(),
+ ) : Profile {
+ val config = TestConfig(this)
+ }
+
+ class TestConfig(profile: Profile) {
+ var prop by RedirectDelegate(profile, { it?.value }, { it?.let { Boxed(it, false) } })
+ var normal by StringDelegate(profile, "test")
+ }
+
+ class Boxed(val value: Int, val unused: Boolean) {
+
+ override fun equals(other: Any?): Boolean {
+ if (other !is Boxed) return false
+ return other.value == this.value
+ }
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/config/profile/delegate/types/RedirectDelegate.kt b/src/main/java/de/bixilon/minosoft/config/profile/delegate/types/RedirectDelegate.kt
new file mode 100644
index 000000000..19561ac56
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/config/profile/delegate/types/RedirectDelegate.kt
@@ -0,0 +1,36 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 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.profile.delegate.types
+
+import de.bixilon.kutil.observer.DataObserver
+import de.bixilon.minosoft.config.profile.delegate.AbstractProfileDelegate
+import de.bixilon.minosoft.config.profile.profiles.Profile
+import kotlin.reflect.KProperty
+
+class RedirectDelegate(
+ override val profile: Profile,
+ val serializer: (V?) -> S?,
+ val lookup: (S?) -> V?,
+) : DataObserver(null), AbstractProfileDelegate {
+
+
+ override fun setValue(thisRef: Any, property: KProperty<*>, value: V?) {
+ super.setValue(thisRef, property, value)
+ invalidate()
+ }
+
+ // fun setValue(thisRef: Any, property: KProperty<*>, value: S?) {
+// setValue(thisRef, property, lookup(value))
+// }
+}
diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/account/AccountProfile.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/account/AccountProfile.kt
index ce85dc408..ffc52dade 100644
--- a/src/main/java/de/bixilon/minosoft/config/profile/profiles/account/AccountProfile.kt
+++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/account/AccountProfile.kt
@@ -13,15 +13,11 @@
package de.bixilon.minosoft.config.profile.profiles.account
-import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonInclude
-import com.fasterxml.jackson.annotation.JsonProperty
-import de.bixilon.kutil.delegates.BackingDelegate
-import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.minosoft.config.profile.ProfileLock
import de.bixilon.minosoft.config.profile.ProfileType
import de.bixilon.minosoft.config.profile.delegate.primitive.BooleanDelegate
-import de.bixilon.minosoft.config.profile.delegate.types.NullableStringDelegate
+import de.bixilon.minosoft.config.profile.delegate.types.RedirectDelegate
import de.bixilon.minosoft.config.profile.delegate.types.StringDelegate
import de.bixilon.minosoft.config.profile.delegate.types.map.MapDelegate
import de.bixilon.minosoft.config.profile.profiles.Profile
@@ -62,19 +58,7 @@ class AccountProfile(
var entries: MutableMap by MapDelegate(this, mutableMapOf())
private set
- /**
- * The current id of the selected account
- */
- @get:JsonInclude(JsonInclude.Include.NON_NULL)
- @get:JsonProperty("selected")
- private var _selected: String? by NullableStringDelegate(this, null)
-
- @get:JsonIgnore
- var selected: Account? by BackingDelegate(get = { entries[_selected] }, set = { _selected = it?.id })
-
- init {
- this::_selected.observe(this) { this.selected = entries[it] }
- }
+ var selected: Account? by RedirectDelegate(this, { it?.id }, { entries[it] })
override fun toString(): String {
return storage?.toString() ?: super.toString()
diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/entries/ErosServer.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/entries/ErosServer.kt
index 28417571e..7422599e9 100644
--- a/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/entries/ErosServer.kt
+++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/eros/server/entries/ErosServer.kt
@@ -14,16 +14,12 @@
package de.bixilon.minosoft.config.profile.profiles.eros.server.entries
import com.fasterxml.jackson.annotation.JacksonInject
-import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonInclude
-import com.fasterxml.jackson.annotation.JsonProperty
-import de.bixilon.kutil.cast.CastUtil.unsafeCast
-import de.bixilon.kutil.delegates.BackingDelegate
-import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.minosoft.assets.util.HashTypes
import de.bixilon.minosoft.config.profile.delegate.SimpleDelegate
import de.bixilon.minosoft.config.profile.delegate.primitive.BooleanDelegate
import de.bixilon.minosoft.config.profile.delegate.types.NullableStringDelegate
+import de.bixilon.minosoft.config.profile.delegate.types.RedirectDelegate
import de.bixilon.minosoft.config.profile.delegate.types.map.MapDelegate
import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfile
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
@@ -67,16 +63,8 @@ class ErosServer(
@get:JsonInclude(JsonInclude.Include.NON_EMPTY)
override var profiles: MutableMap by MapDelegate(profile, profiles)
- @get:JsonProperty("forced_version")
@get:JsonInclude(JsonInclude.Include.NON_NULL)
- private var _forcedVersion by NullableStringDelegate(profile, forcedVersion.unsafeCast()?.name)
-
- @get:JsonIgnore
- override var forcedVersion by BackingDelegate(get = { Versions[_forcedVersion] }, set = { _forcedVersion = it?.name })
-
- init {
- this::_forcedVersion.observe(this) { this.forcedVersion = Versions[it] }
- }
+ override var forcedVersion: Version? by RedirectDelegate(profile, { it?.name }, { Versions[it] })
@get:JsonInclude(JsonInclude.Include.NON_DEFAULT)
override var faviconHash: String? by NullableStringDelegate(profile, null) { if (it != null) check(it.length == HashTypes.SHA256.length) { "Not a valid sha256 hash!" } }
diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/dialog/profiles/ProfileCreateDialog.kt b/src/main/java/de/bixilon/minosoft/gui/eros/dialog/profiles/ProfileCreateDialog.kt
index 433719b62..84e621570 100644
--- a/src/main/java/de/bixilon/minosoft/gui/eros/dialog/profiles/ProfileCreateDialog.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/eros/dialog/profiles/ProfileCreateDialog.kt
@@ -14,9 +14,9 @@
package de.bixilon.minosoft.gui.eros.dialog.profiles
import de.bixilon.kutil.cast.CastUtil.unsafeCast
+import de.bixilon.minosoft.config.profile.ProfileUtil.isValidName
import de.bixilon.minosoft.config.profile.manager.ProfileManagers
import de.bixilon.minosoft.config.profile.profiles.Profile
-import de.bixilon.minosoft.config.profile.storage.ProfileIOUtil.isValidName
import de.bixilon.minosoft.config.profile.storage.StorageProfileManager
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
import de.bixilon.minosoft.gui.eros.controller.JavaFXWindowController