registry: use reflections to set parent

This commit is contained in:
Bixilon 2021-04-03 19:04:54 +02:00
parent 32c1b4eb8a
commit 41b32fb466
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
9 changed files with 70 additions and 66 deletions

View File

@ -26,7 +26,6 @@ import de.bixilon.minosoft.data.inventory.ItemNBTValues.UNBREAKABLE_TAG
import de.bixilon.minosoft.data.mappings.Enchantment
import de.bixilon.minosoft.data.mappings.items.Item
import de.bixilon.minosoft.data.mappings.versions.Version
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.util.BitByte
import de.bixilon.minosoft.util.nbt.tag.*
@ -110,7 +109,7 @@ class ItemStack(
additionalNBT = nbt
}
fun getNbt(mapping: VersionMapping): CompoundTag {
fun getNBT(): CompoundTag {
val nbt = additionalNBT?.clone() ?: CompoundTag()
if (repairCost != 0) {
nbt.writeTag(REPAIR_COST_TAG, IntTag(repairCost))
@ -147,13 +146,13 @@ class ItemStack(
val enchantmentTag = CompoundTag()
enchantmentTag.writeTag(ENCHANTMENT_ID_TAG, StringTag(id.toString()))
enchantmentTag.writeTag(ENCHANTMENT_LEVEL_TAG, if (mapping.version!!.isFlattened()) {
enchantmentTag.writeTag(ENCHANTMENT_LEVEL_TAG, if (version!!.isFlattened()) {
IntTag(level)
} else {
ShortTag(level.toShort())
})
}
if (mapping.version!!.isFlattened()) {
if (version!!.isFlattened()) {
nbt.writeTag(ENCHANTMENT_FLATTENING_TAG, enchantmentList)
} else {
nbt.writeTag(ENCHANTMENT_PRE_FLATTENING_TAG, enchantmentList)

View File

@ -24,7 +24,7 @@ class EnumRegistry<T : Enum<*>>(
private var parentRegistry: EnumRegistry<T>? = null,
var values: ValuesEnum<T>,
private val mutable: Boolean = true,
) : Clearable {
) : Clearable, Parentable<EnumRegistry<T>> {
private var initialized = false
private val idValueMap: MutableMap<Int, T> = mutableMapOf()
private val valueIdMap: MutableMap<T, Int> = mutableMapOf()
@ -37,11 +37,11 @@ class EnumRegistry<T : Enum<*>>(
return valueIdMap[value] ?: parentRegistry?.getId(value)!!
}
fun setParent(registry: EnumRegistry<T>?) {
override fun setParent(parent: EnumRegistry<T>?) {
if (!mutable) {
throw IllegalStateException("Registry is immutable!")
}
this.parentRegistry = registry
this.parentRegistry = parent
}
private fun getEnum(data: Any): T {

View File

@ -19,7 +19,7 @@ import de.bixilon.minosoft.util.collections.Clearable
class FakeEnumRegistry<T : RegistryFakeEnumerable>(
private var parentRegistry: FakeEnumRegistry<T>? = null,
) : Clearable {
) : Clearable, Parentable<FakeEnumRegistry<T>> {
private var initialized = false
private val idValueMap: MutableMap<Int, T> = mutableMapOf()
private val valueIdMap: MutableMap<T, Int> = mutableMapOf()
@ -37,9 +37,9 @@ class FakeEnumRegistry<T : RegistryFakeEnumerable>(
return valueIdMap[value] ?: parentRegistry?.getId(value)!!
}
fun setParent(registry: FakeEnumRegistry<T>?) {
check(registry !== this) { "Can not set our self as parent!" }
this.parentRegistry = registry
override fun setParent(parent: FakeEnumRegistry<T>?) {
check(parent !== this) { "Can not set our self as parent!" }
this.parentRegistry = parent
}
fun initialize(data: JsonObject?, mappings: VersionMapping, deserializer: IdDeserializer<T>): FakeEnumRegistry<T> {

View File

@ -0,0 +1,19 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.registry
interface Parentable<T> {
fun setParent(parent: T?)
}

View File

@ -21,7 +21,7 @@ import de.bixilon.minosoft.util.json.ResourceLocationJsonMap.toResourceLocationM
open class Registry<T : RegistryItem>(
private var parentRegistry: Registry<T>? = null,
) : Iterable<T>, Clearable {
) : Iterable<T>, Clearable, Parentable<Registry<T>> {
private var initialized = false
private val idValueMap: MutableMap<Int, T> = mutableMapOf()
private val valueIdMap: MutableMap<T, Int> = mutableMapOf()
@ -40,8 +40,8 @@ open class Registry<T : RegistryItem>(
return valueIdMap[value] ?: parentRegistry?.getId(value)!!
}
fun setParent(registry: Registry<T>?) {
this.parentRegistry = registry
override fun setParent(parent: Registry<T>?) {
this.parentRegistry = parent
}
open fun initialize(data: Map<ResourceLocation, JsonObject>?, mappings: VersionMapping?, deserializer: ResourceLocationDeserializer<T>, flattened: Boolean = true, metaType: MetaTypes = MetaTypes.NONE): Registry<T> {

View File

@ -36,7 +36,7 @@ data class Version(
) {
var isLoaded = false
var isGettingLoaded = false
val mapping: VersionMapping = VersionMapping(this)
val mapping: VersionMapping = VersionMapping()
lateinit var assetsManager: MinecraftAssetsManager
lateinit var localeManager: MinecraftLocaleManager
@ -110,8 +110,7 @@ data class Version(
JsonObject()
}
latch.addCount(1)
mapping.version = this
mapping.load(pixlyzerData)
mapping.load(this, pixlyzerData)
latch.countDown()
if (pixlyzerData.size() > 0) {
Log.verbose(String.format("Loaded mappings for version %s in %dms (%s)", this, (System.currentTimeMillis() - startTime), versionName))

View File

@ -31,10 +31,7 @@ import de.bixilon.minosoft.data.mappings.items.Item
import de.bixilon.minosoft.data.mappings.items.ItemRegistry
import de.bixilon.minosoft.data.mappings.materials.Material
import de.bixilon.minosoft.data.mappings.particle.Particle
import de.bixilon.minosoft.data.mappings.registry.EnumRegistry
import de.bixilon.minosoft.data.mappings.registry.FakeEnumRegistry
import de.bixilon.minosoft.data.mappings.registry.PerEnumVersionRegistry
import de.bixilon.minosoft.data.mappings.registry.Registry
import de.bixilon.minosoft.data.mappings.registry.*
import de.bixilon.minosoft.data.mappings.statistics.Statistic
import de.bixilon.minosoft.gui.rendering.chunk.VoxelShape
import de.bixilon.minosoft.gui.rendering.chunk.models.AABB
@ -43,10 +40,11 @@ import de.bixilon.minosoft.protocol.packets.clientbound.play.title.TitlePacketFa
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.collections.Clearable
import de.bixilon.minosoft.util.json.ResourceLocationJsonMap.toResourceLocationMap
import java.lang.reflect.Field
import java.util.*
class VersionMapping(var version: Version?) {
class VersionMapping {
var shapes: MutableList<VoxelShape> = mutableListOf()
val motiveRegistry: Registry<Motive> = Registry()
val blockRegistry: Registry<Block> = Registry()
@ -94,32 +92,9 @@ class VersionMapping(var version: Version?) {
set(value) {
_parentMapping = value
// ToDo: Use reflections for this
motiveRegistry.setParent(value?.motiveRegistry)
itemRegistry.setParent(value?.itemRegistry)
enchantmentRegistry.setParent(value?.enchantmentRegistry)
particleRegistry.setParent(value?.particleRegistry)
statusEffectRegistry.setParent(value?.statusEffectRegistry)
blockRegistry.setParent(value?.blockRegistry)
statisticRegistry.setParent(value?.statisticRegistry)
biomeRegistry.setParent(value?.biomeRegistry)
dimensionRegistry.setParent(value?.dimensionRegistry)
biomePrecipitationRegistry.setParent(value?.biomePrecipitationRegistry)
biomeCategoryRegistry.setParent(value?.biomeCategoryRegistry)
materialRegistry.setParent(value?.materialRegistry)
villagerProfessionRegistry.setParent(value?.villagerProfessionRegistry)
equipmentSlotRegistry.setParent(value?.equipmentSlotRegistry)
handEquipmentSlotRegistry.setParent(value?.handEquipmentSlotRegistry)
armorEquipmentSlotRegistry.setParent(value?.armorEquipmentSlotRegistry)
armorStandEquipmentSlotRegistry.setParent(value?.armorStandEquipmentSlotRegistry)
entityMetaDataDataDataTypesRegistry.setParent(value?.entityMetaDataDataDataTypesRegistry)
creativeModeTabRegistry.setParent(value?.creativeModeTabRegistry)
titleActionsRegistry.setParent(value?.titleActionsRegistry)
entityRegistry.setParent(value?.entityRegistry)
for (field in PARENTABLE_FIELDS) {
PARENTABLE_SET_PARENT_METHOD.invoke(field.get(this), value?.let { field.get(it) })
}
}
fun getBlockState(blockState: Int): BlockState? {
@ -133,30 +108,29 @@ class VersionMapping(var version: Version?) {
return entityMetaIndexMap[field] ?: _parentMapping?.getEntityMetaDataIndex(field)
}
private fun <T : Enum<*>> loadEnumRegistry(data: JsonElement?, registry: EnumRegistry<T>, alternative: PerEnumVersionRegistry<T>) {
private fun <T : Enum<*>> loadEnumRegistry(version: Version, data: JsonElement?, registry: EnumRegistry<T>, alternative: PerEnumVersionRegistry<T>) {
data?.let {
registry.initialize(it)
} ?: let {
registry.setParent(alternative.forVersion(version!!))
registry.setParent(alternative.forVersion(version))
}
}
fun load(pixlyzerData: JsonObject) {
val version = version!!
fun load(version: Version, pixlyzerData: JsonObject) {
// pre init stuff
loadShapes(pixlyzerData["shapes"]?.asJsonObject)
loadBlockModels(pixlyzerData["models"].asJsonObject.toResourceLocationMap())
// enums
loadEnumRegistry(pixlyzerData["equipment_slots"], equipmentSlotRegistry, DefaultRegistries.EQUIPMENT_SLOTS_REGISTRY)
loadEnumRegistry(pixlyzerData["hand_equipment_slots"], handEquipmentSlotRegistry, DefaultRegistries.HAND_EQUIPMENT_SLOTS_REGISTRY)
loadEnumRegistry(pixlyzerData["armor_equipment_slots"], armorEquipmentSlotRegistry, DefaultRegistries.ARMOR_EQUIPMENT_SLOTS_REGISTRY)
loadEnumRegistry(pixlyzerData["armor_stand_equipment_slots"], armorStandEquipmentSlotRegistry, DefaultRegistries.ARMOR_STAND_EQUIPMENT_SLOTS_REGISTRY)
loadEnumRegistry(version, pixlyzerData["equipment_slots"], equipmentSlotRegistry, DefaultRegistries.EQUIPMENT_SLOTS_REGISTRY)
loadEnumRegistry(version, pixlyzerData["hand_equipment_slots"], handEquipmentSlotRegistry, DefaultRegistries.HAND_EQUIPMENT_SLOTS_REGISTRY)
loadEnumRegistry(version, pixlyzerData["armor_equipment_slots"], armorEquipmentSlotRegistry, DefaultRegistries.ARMOR_EQUIPMENT_SLOTS_REGISTRY)
loadEnumRegistry(version, pixlyzerData["armor_stand_equipment_slots"], armorStandEquipmentSlotRegistry, DefaultRegistries.ARMOR_STAND_EQUIPMENT_SLOTS_REGISTRY)
loadEnumRegistry(pixlyzerData["entity_meta_data_data_types"], entityMetaDataDataDataTypesRegistry, DefaultRegistries.ENTITY_META_DATA_DATA_TYPES_REGISTRY)
loadEnumRegistry(version, pixlyzerData["entity_meta_data_data_types"], entityMetaDataDataDataTypesRegistry, DefaultRegistries.ENTITY_META_DATA_DATA_TYPES_REGISTRY)
loadEnumRegistry(pixlyzerData["title_actions"], titleActionsRegistry, DefaultRegistries.TITLE_ACTIONS_REGISTRY)
loadEnumRegistry(version, pixlyzerData["title_actions"], titleActionsRegistry, DefaultRegistries.TITLE_ACTIONS_REGISTRY)
// id stuff
biomeCategoryRegistry.initialize(pixlyzerData["biome_categories"]?.asJsonObject, this, BiomeCategory)
@ -242,4 +216,22 @@ class VersionMapping(var version: Version?) {
field.javaClass.getMethod("clear").invoke(this)
}
}
companion object {
private val PARENTABLE_FIELDS: List<Field>
private val PARENTABLE_SET_PARENT_METHOD = Parentable::class.java.getDeclaredMethod("setParent", Any::class.java)
init {
val fields: MutableList<Field> = mutableListOf()
for (field in VersionMapping::class.java.declaredFields) {
if (!Parentable::class.java.isAssignableFrom(field.type)) {
continue
}
fields.add(field)
}
PARENTABLE_FIELDS = fields.toList()
}
}
}

View File

@ -75,7 +75,7 @@ public class Connection {
private int desiredVersionNumber = -1;
private ServerAddress address;
private Version version = Versions.LOWEST_VERSION_SUPPORTED; // default
private final VersionMapping customMapping = new VersionMapping(this.version);
private final VersionMapping customMapping = new VersionMapping();
private ConnectionStates state = ConnectionStates.DISCONNECTED;
private ConnectionReasons reason;
private ConnectionReasons nextReason;
@ -144,7 +144,6 @@ public class Connection {
setVersion(version);
try {
version.load(latch); // ToDo: show gui loader
this.customMapping.setVersion(version);
this.customMapping.setParentMapping(version.getMapping());
this.player = new Player(this.account, this);
@ -159,10 +158,6 @@ public class Connection {
} catch (Throwable exception) {
Log.printException(exception, LogLevels.DEBUG);
Log.fatal(String.format("Could not load version %s. This version seems to be unsupported!", version));
if (this.customMapping.getVersion() != null) {
this.customMapping.getVersion().getMapping().setParentMapping(null);
}
this.customMapping.setVersion(null);
version.unload();
this.lastException = new MappingsLoadingException("Mappings could not be loaded", exception);
setConnectionState(ConnectionStates.FAILED_NO_RETRY);

View File

@ -190,7 +190,7 @@ public class OutByteBuffer {
writeShort((short) this.connection.getMapping().getItemRegistry().getId(itemStack.getItem()));
writeByte((byte) itemStack.getItemCount());
writeShort((short) itemStack.getItemMetadata());
writeNBT(itemStack.getNbt(this.connection.getMapping()));
writeNBT(itemStack.getNBT());
}
if (itemStack == null) {
writeBoolean(false);
@ -198,7 +198,7 @@ public class OutByteBuffer {
}
writeVarInt(this.connection.getMapping().getItemRegistry().getId(itemStack.getItem()));
writeByte((byte) itemStack.getItemCount());
writeNBT(itemStack.getNbt(this.connection.getMapping()));
writeNBT(itemStack.getNBT());
}
void writeNBT(CompoundTag nbt) {