From c0a5018b83219b2670a2fec1baf1fa9e5cb5ced6 Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Sun, 8 Oct 2023 18:40:14 +0200 Subject: [PATCH] custom deserializer for accounts That makes the polymorphism dynamic and not at compile time anymore. It allows using proper resource locations (with no namespace) and allows mods to add custom accounts --- .../minosoft/assets/util/InputStreamUtil.kt | 3 +- .../bixilon/minosoft/data/accounts/Account.kt | 11 ----- .../accounts/types/AccountTypes.kt} | 24 +++++----- .../data/entities/event/EntityEvents.kt | 6 +-- .../registries/fallback/FallbackRegistries.kt | 7 ++- .../minosoft/util/json/AccountDeserializer.kt | 44 +++++++++++++++++++ .../de/bixilon/minosoft/util/json/Jackson.kt | 1 + 7 files changed, 63 insertions(+), 33 deletions(-) rename src/main/java/de/bixilon/minosoft/{util/json/ResourceLocationJsonMap.kt => data/accounts/types/AccountTypes.kt} (61%) create mode 100644 src/main/java/de/bixilon/minosoft/util/json/AccountDeserializer.kt diff --git a/src/main/java/de/bixilon/minosoft/assets/util/InputStreamUtil.kt b/src/main/java/de/bixilon/minosoft/assets/util/InputStreamUtil.kt index c015d445b..fbd8f1ce0 100644 --- a/src/main/java/de/bixilon/minosoft/assets/util/InputStreamUtil.kt +++ b/src/main/java/de/bixilon/minosoft/assets/util/InputStreamUtil.kt @@ -16,6 +16,7 @@ package de.bixilon.minosoft.assets.util import com.fasterxml.jackson.module.kotlin.readValue import de.bixilon.kutil.buffer.BufferDefinition import de.bixilon.kutil.cast.CastUtil.unsafeCast +import de.bixilon.kutil.json.JsonObject import de.bixilon.mbf.MBFBinaryReader import de.bixilon.minosoft.util.json.Jackson import de.matthiasmann.twl.utils.PNGDecoder @@ -46,7 +47,7 @@ object InputStreamUtil { return builder.toString() } - fun InputStream.readJsonObject(close: Boolean = true): Map { + fun InputStream.readJsonObject(close: Boolean = true): JsonObject { try { return Jackson.MAPPER.readValue(this, Jackson.JSON_MAP_TYPE) } finally { diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/Account.kt b/src/main/java/de/bixilon/minosoft/data/accounts/Account.kt index 74b767638..5c921e9fd 100644 --- a/src/main/java/de/bixilon/minosoft/data/accounts/Account.kt +++ b/src/main/java/de/bixilon/minosoft/data/accounts/Account.kt @@ -14,28 +14,17 @@ package de.bixilon.minosoft.data.accounts import com.fasterxml.jackson.annotation.JsonIgnore -import com.fasterxml.jackson.annotation.JsonSubTypes -import com.fasterxml.jackson.annotation.JsonTypeInfo import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf import de.bixilon.kutil.latch.AbstractLatch import de.bixilon.kutil.observer.DataObserver.Companion.observed import de.bixilon.minosoft.config.profile.profiles.account.AccountProfileManager import de.bixilon.minosoft.config.profile.profiles.eros.server.entries.AbstractServer -import de.bixilon.minosoft.data.accounts.types.microsoft.MicrosoftAccount -import de.bixilon.minosoft.data.accounts.types.mojang.MojangAccount -import de.bixilon.minosoft.data.accounts.types.offline.OfflineAccount import de.bixilon.minosoft.data.entities.entities.player.properties.PlayerProperties import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.util.account.minecraft.MinecraftPrivateKey import java.util.* -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") -@JsonSubTypes( - JsonSubTypes.Type(value = MojangAccount::class, name = "minosoft:mojang_account"), - JsonSubTypes.Type(value = OfflineAccount::class, name = "minosoft:offline_account"), - JsonSubTypes.Type(value = MicrosoftAccount::class, name = "minosoft:microsoft_account"), -) abstract class Account( val username: String, ) { diff --git a/src/main/java/de/bixilon/minosoft/util/json/ResourceLocationJsonMap.kt b/src/main/java/de/bixilon/minosoft/data/accounts/types/AccountTypes.kt similarity index 61% rename from src/main/java/de/bixilon/minosoft/util/json/ResourceLocationJsonMap.kt rename to src/main/java/de/bixilon/minosoft/data/accounts/types/AccountTypes.kt index 78f64c543..3ebf57902 100644 --- a/src/main/java/de/bixilon/minosoft/util/json/ResourceLocationJsonMap.kt +++ b/src/main/java/de/bixilon/minosoft/data/accounts/types/AccountTypes.kt @@ -11,20 +11,16 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.util.json +package de.bixilon.minosoft.data.accounts.types -import de.bixilon.kutil.cast.CastUtil.unsafeCast -import de.bixilon.minosoft.data.registries.identified.ResourceLocation +import de.bixilon.minosoft.data.accounts.types.microsoft.MicrosoftAccount +import de.bixilon.minosoft.data.accounts.types.mojang.MojangAccount +import de.bixilon.minosoft.data.accounts.types.offline.OfflineAccount -object ResourceLocationJsonMap { - - fun Map<*, *>.toResourceLocationMap(): Map { - val ret: MutableMap = mutableMapOf() - - for ((key, value) in this) { - ret[ResourceLocation.of(key.unsafeCast())] = value.unsafeCast() - } - - return ret - } +object AccountTypes { + val types = mutableMapOf( + MicrosoftAccount.identifier to MicrosoftAccount::class, + MojangAccount.identifier to MojangAccount::class, + OfflineAccount.identifier to OfflineAccount::class, + ) } diff --git a/src/main/java/de/bixilon/minosoft/data/entities/event/EntityEvents.kt b/src/main/java/de/bixilon/minosoft/data/entities/event/EntityEvents.kt index 18d3b941f..ae64af55a 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/event/EntityEvents.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/event/EntityEvents.kt @@ -17,15 +17,15 @@ import de.bixilon.kutil.cast.CollectionCast.asAnyMap import de.bixilon.kutil.json.JsonUtil.asJsonObject import de.bixilon.kutil.primitive.IntUtil.toInt import de.bixilon.minosoft.Minosoft -import de.bixilon.minosoft.assets.util.InputStreamUtil.readJsonObject +import de.bixilon.minosoft.assets.util.InputStreamUtil.readJson import de.bixilon.minosoft.data.entities.entities.Entity import de.bixilon.minosoft.data.entities.event.events.damage.* import de.bixilon.minosoft.data.registries.entities.DefaultEntityFactories import de.bixilon.minosoft.data.registries.factory.DefaultFactory import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft +import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.protocol.versions.Version import de.bixilon.minosoft.util.KUtil.toResourceLocation -import de.bixilon.minosoft.util.json.ResourceLocationJsonMap.toResourceLocationMap import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogMessageType @@ -58,7 +58,7 @@ object EntityEvents : DefaultFactory>( } fun load() { - val json = Minosoft.MINOSOFT_ASSETS_MANAGER[FILE].readJsonObject().toResourceLocationMap() + val json: Map = Minosoft.MINOSOFT_ASSETS_MANAGER[FILE].readJson() for ((name, data) in json) { val clazz = DefaultEntityFactories.ABSTRACT_ENTITY_DATA_CLASSES[name]?.java ?: DefaultEntityFactories[name]?.javaClass // TODO: This is the companion class if (clazz == null) { diff --git a/src/main/java/de/bixilon/minosoft/data/registries/fallback/FallbackRegistries.kt b/src/main/java/de/bixilon/minosoft/data/registries/fallback/FallbackRegistries.kt index d5e406d38..5cbca6338 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/fallback/FallbackRegistries.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/fallback/FallbackRegistries.kt @@ -15,7 +15,7 @@ package de.bixilon.minosoft.data.registries.fallback import de.bixilon.kutil.json.JsonUtil.asJsonObject import de.bixilon.minosoft.Minosoft -import de.bixilon.minosoft.assets.util.InputStreamUtil.readJsonObject +import de.bixilon.minosoft.assets.util.InputStreamUtil.readJson import de.bixilon.minosoft.data.container.equipment.EquipmentSlots import de.bixilon.minosoft.data.entities.EntityAnimations import de.bixilon.minosoft.data.entities.EntityObjectType @@ -34,7 +34,6 @@ import de.bixilon.minosoft.data.registries.registries.registry.Registry import de.bixilon.minosoft.data.registries.registries.registry.ResourceLocationRegistry import de.bixilon.minosoft.protocol.packets.c2s.play.entity.EntityActionC2SP import de.bixilon.minosoft.protocol.packets.s2c.play.title.TitleS2CF -import de.bixilon.minosoft.util.json.ResourceLocationJsonMap.toResourceLocationMap import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogMessageType @@ -77,7 +76,7 @@ object FallbackRegistries { check(!initialized) { "Already initialized!" } Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Loading default registries..." } - val enumJson = Minosoft.MINOSOFT_ASSETS_MANAGER[ENUM_RESOURCE_LOCATION].readJsonObject().toResourceLocationMap() + val enumJson: Map = Minosoft.MINOSOFT_ASSETS_MANAGER[ENUM_RESOURCE_LOCATION].readJson() EQUIPMENT_SLOTS_REGISTRY.initialize(enumJson[ResourceLocation.of("equipment_slots")].asJsonObject()) HAND_EQUIPMENT_SLOTS_REGISTRY.initialize(enumJson[ResourceLocation.of("hand_equipment_slots")].asJsonObject()) @@ -92,7 +91,7 @@ object FallbackRegistries { ENTITY_ACTIONS_REGISTRY.initialize(enumJson[ResourceLocation.of("entity_actions")].asJsonObject()) - val registriesJson = Minosoft.MINOSOFT_ASSETS_MANAGER[REGISTRIES_RESOURCE_LOCATION].readJsonObject().toResourceLocationMap() + val registriesJson: Map = Minosoft.MINOSOFT_ASSETS_MANAGER[REGISTRIES_RESOURCE_LOCATION].readJson() DEFAULT_PLUGIN_CHANNELS_REGISTRY.initialize(registriesJson[ResourceLocation.of("default_channels")].asJsonObject(), PluginChannel) diff --git a/src/main/java/de/bixilon/minosoft/util/json/AccountDeserializer.kt b/src/main/java/de/bixilon/minosoft/util/json/AccountDeserializer.kt new file mode 100644 index 000000000..d2990e7aa --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/json/AccountDeserializer.kt @@ -0,0 +1,44 @@ +/* + * 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.util.json + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import de.bixilon.kutil.json.JsonObject +import de.bixilon.minosoft.data.accounts.Account +import de.bixilon.minosoft.data.accounts.types.AccountTypes +import de.bixilon.minosoft.util.KUtil.toResourceLocation + + +object AccountDeserializer : SimpleModule() { + + init { + addDeserializer(Account::class.java, Deserializer) + } + + object Deserializer : StdDeserializer(Account::class.java) { + + override fun deserialize(parser: JsonParser, context: DeserializationContext?): Account { + val codec = parser.codec + val root = codec.readValue(parser, Jackson.JSON_MAP_TYPE) + + val type = root["type"].toResourceLocation() + val clazz = AccountTypes.types[type] ?: throw IllegalArgumentException("Can not find account type $type!") + + return Jackson.MAPPER.convertValue(root, clazz.java) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/util/json/Jackson.kt b/src/main/java/de/bixilon/minosoft/util/json/Jackson.kt index b8da37075..75a6b210b 100644 --- a/src/main/java/de/bixilon/minosoft/util/json/Jackson.kt +++ b/src/main/java/de/bixilon/minosoft/util/json/Jackson.kt @@ -46,6 +46,7 @@ object Jackson { ) .registerModule(JavaTimeModule()) .registerModule(ResourceLocationSerializer) + .registerModule(AccountDeserializer) .registerModule(RGBColorSerializer) .registerModule(ChatComponentColorSerializer) .registerModule(Vec2Serializer)