diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/DefaultBlockEntityMetaDataFactory.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/DefaultBlockEntityMetaDataFactory.kt index e4791aeff..9d1960707 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/DefaultBlockEntityMetaDataFactory.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/DefaultBlockEntityMetaDataFactory.kt @@ -17,6 +17,7 @@ import de.bixilon.minosoft.data.entities.block.container.* import de.bixilon.minosoft.data.entities.block.container.storage.* import de.bixilon.minosoft.data.entities.block.piston.PistonBlockEntity import de.bixilon.minosoft.data.entities.block.piston.StickyPistonBlockEntity +import de.bixilon.minosoft.data.mappings.MultiResourceLocationAble import de.bixilon.minosoft.data.mappings.ResourceLocation import de.bixilon.minosoft.protocol.network.connection.PlayConnection @@ -67,6 +68,11 @@ object DefaultBlockEntityMetaDataFactory { for (entityFactory in entityFactories) { ret[entityFactory.RESOURCE_LOCATION] = entityFactory + if (entityFactory is MultiResourceLocationAble) { + for (resourceLocation in entityFactory.ALIASES) { + ret[resourceLocation] = entityFactory + } + } } BLOCK_ENTITY_FACTORY_MAP = ret.toMap() diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/ShulkerBoxBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/ShulkerBoxBlockEntity.kt index a8e409a8d..da2698f2e 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/ShulkerBoxBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/container/storage/ShulkerBoxBlockEntity.kt @@ -14,14 +14,23 @@ package de.bixilon.minosoft.data.entities.block.container.storage import de.bixilon.minosoft.data.entities.block.BlockEntityFactory +import de.bixilon.minosoft.data.mappings.MultiResourceLocationAble import de.bixilon.minosoft.data.mappings.ResourceLocation import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.util.KUtil.toResourceLocationList class ShulkerBoxBlockEntity(connection: PlayConnection) : StorageBlockEntity(connection) { - companion object : BlockEntityFactory { + companion object : BlockEntityFactory, MultiResourceLocationAble { override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("minecraft:shulker_box") + override val ALIASES: Set = setOf( + "minecraft:white_shulker_box", "minecraft:orange_shulker_box", "minecraft:magenta_shulker_box", "minecraft:light_blue_shulker_box", + "minecraft:yellow_shulker_box", "minecraft:lime_shulker_box", "minecraft:pink_shulker_box", "minecraft:gray_shulker_box", + "minecraft:silver_shulker_box", "minecraft:cyan_shulker_box", "minecraft:purple_shulker_box", "minecraft:blue_shulker_box", + "minecraft:brown_shulker_box", "minecraft:green_shulker_box", "minecraft:red_shulker_box", "minecraft:black_shulker_box", + ).toResourceLocationList() + override fun build(connection: PlayConnection): ShulkerBoxBlockEntity { return ShulkerBoxBlockEntity(connection) diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/MultiResourceLocationAble.kt b/src/main/java/de/bixilon/minosoft/data/mappings/MultiResourceLocationAble.kt new file mode 100644 index 000000000..8acc40ea5 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/mappings/MultiResourceLocationAble.kt @@ -0,0 +1,18 @@ +/* + * 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.data.mappings + +interface MultiResourceLocationAble { + val ALIASES: Set +} diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/Block.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/Block.kt index a4ec8136d..a046bb23f 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/Block.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/Block.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.data.mappings.blocks import com.google.gson.JsonObject import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.mappings.blocks.entites.BlockEntityType import de.bixilon.minosoft.data.mappings.items.Item import de.bixilon.minosoft.data.mappings.registry.RegistryItem import de.bixilon.minosoft.data.mappings.registry.ResourceLocationDeserializer @@ -22,12 +23,14 @@ import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.gui.rendering.TintColorCalculator import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.BlockLikeRenderer -open class Block(override val resourceLocation: ResourceLocation, mappings: VersionMapping, data: JsonObject) : RegistryItem { +open class Block(final override val resourceLocation: ResourceLocation, mappings: VersionMapping, data: JsonObject) : RegistryItem { open val explosionResistance: Float = data["explosion_resistance"]?.asFloat ?: 0.0f open val tintColor: RGBColor? = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) } open val randomOffsetType: RandomOffsetTypes? = data["offset_type"]?.asString?.let { RandomOffsetTypes[it] } open val tint: ResourceLocation? = data["tint"]?.asString?.let { ResourceLocation(it) } open val renderOverride: List? = null + open var blockEntityType: BlockEntityType? = null + protected set private val itemId: Int = data["item"]?.asInt ?: 0 @@ -39,7 +42,8 @@ open class Block(override val resourceLocation: ResourceLocation, mappings: Vers protected set override fun postInit(versionMapping: VersionMapping) { - item = versionMapping.itemRegistry.get(itemId) + item = versionMapping.itemRegistry[itemId] + blockEntityType = versionMapping.blockEntityTypeRegistry.getByBlock(this) } override fun toString(): String { diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/entites/BlockEntityType.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/entites/BlockEntityType.kt index a4fd7f85d..b61be11ae 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/entites/BlockEntityType.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/entites/BlockEntityType.kt @@ -18,6 +18,7 @@ import de.bixilon.minosoft.data.entities.block.BlockEntity import de.bixilon.minosoft.data.entities.block.BlockEntityFactory import de.bixilon.minosoft.data.entities.block.DefaultBlockEntityMetaDataFactory import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.mappings.blocks.Block import de.bixilon.minosoft.data.mappings.registry.RegistryItem import de.bixilon.minosoft.data.mappings.registry.ResourceLocationDeserializer import de.bixilon.minosoft.data.mappings.versions.VersionMapping @@ -25,9 +26,22 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection data class BlockEntityType( override val resourceLocation: ResourceLocation, - // ToDo: Block ids, more? + private var blockIds: Set?, val factory: BlockEntityFactory, ) : RegistryItem { + lateinit var blocks: Set + private set + + override fun postInit(versionMapping: VersionMapping) { + val blocks: MutableSet = mutableSetOf() + + for (blockId in blockIds!!) { + blocks += versionMapping.blockRegistry[blockId] + } + this.blockIds = null + + this.blocks = blocks.toSet() + } fun build(connection: PlayConnection): BlockEntity { return DefaultBlockEntityMetaDataFactory.buildBlockEntity(factory, connection) @@ -37,8 +51,15 @@ data class BlockEntityType( override fun deserialize(mappings: VersionMapping?, resourceLocation: ResourceLocation, data: JsonObject): BlockEntityType? { val factory = DefaultBlockEntityMetaDataFactory.getEntityFactory(resourceLocation) ?: return null // ToDo + val blockIds: MutableSet = mutableSetOf() + + for (blockId in data["blocks"].asJsonArray) { + blockIds += blockId.asInt + } + return BlockEntityType( resourceLocation = resourceLocation, + blockIds = blockIds, factory = factory, ) } diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/entites/BlockEntityTypeRegistry.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/entites/BlockEntityTypeRegistry.kt new file mode 100644 index 000000000..500c9b242 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/entites/BlockEntityTypeRegistry.kt @@ -0,0 +1,44 @@ +/* + * 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.data.mappings.blocks.entites + +import de.bixilon.minosoft.data.mappings.blocks.Block +import de.bixilon.minosoft.data.mappings.registry.Registry +import de.bixilon.minosoft.data.mappings.versions.VersionMapping + +class BlockEntityTypeRegistry( + private val versionMapping: VersionMapping, + private var parentRegistry: BlockEntityTypeRegistry? = null, +) : Registry() { + private lateinit var blockTypeMap: MutableMap + + fun getByBlock(block: Block): BlockEntityType? { + return blockTypeMap[block] ?: parentRegistry?.getByBlock(block) + } + + fun setParent(parent: BlockEntityTypeRegistry?) { + super.setParent(parent) + this.parentRegistry = parent + } + + override fun postInit(versionMapping: VersionMapping) { + super.postInit(versionMapping) + blockTypeMap = mutableMapOf() + for ((_, type) in resourceLocationMap) { + for (block in type.blocks) { + blockTypeMap[block] = type + } + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/registry/Registry.kt b/src/main/java/de/bixilon/minosoft/data/mappings/registry/Registry.kt index 61b7494d6..949403f19 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/registry/Registry.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/registry/Registry.kt @@ -23,20 +23,20 @@ open class Registry( private var parentRegistry: Registry? = null, ) : Iterable, Clearable, Parentable> { private var initialized = false - private val idValueMap: MutableMap = mutableMapOf() - private val valueIdMap: MutableMap = mutableMapOf() - private val resourceLocationMap: MutableMap = mutableMapOf() + protected val idValueMap: MutableMap = mutableMapOf() + protected val valueIdMap: MutableMap = mutableMapOf() + protected val resourceLocationMap: MutableMap = mutableMapOf() - open fun get(resourceLocation: ResourceLocation): T? { + open operator fun get(resourceLocation: ResourceLocation): T? { return resourceLocationMap[resourceLocation] ?: parentRegistry?.get(resourceLocation) } - open fun get(resourceLocation: String): T? { + open operator fun get(resourceLocation: String): T? { return get(ResourceLocation.getPathResourceLocation(resourceLocation)) } - open fun get(id: Int): T { + open operator fun get(id: Int): T { return idValueMap[id] ?: parentRegistry?.get(id)!! } @@ -95,7 +95,7 @@ open class Registry( } - fun postInit(versionMapping: VersionMapping) { + open fun postInit(versionMapping: VersionMapping) { for ((_, value) in resourceLocationMap) { value.postInit(versionMapping) } diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/versions/VersionMapping.kt b/src/main/java/de/bixilon/minosoft/data/mappings/versions/VersionMapping.kt index b3d223508..87923b199 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/versions/VersionMapping.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/versions/VersionMapping.kt @@ -26,6 +26,7 @@ import de.bixilon.minosoft.data.mappings.biomes.BiomePrecipitation import de.bixilon.minosoft.data.mappings.blocks.Block import de.bixilon.minosoft.data.mappings.blocks.BlockState import de.bixilon.minosoft.data.mappings.blocks.entites.BlockEntityType +import de.bixilon.minosoft.data.mappings.blocks.entites.BlockEntityTypeRegistry import de.bixilon.minosoft.data.mappings.effects.StatusEffect import de.bixilon.minosoft.data.mappings.entities.EntityType import de.bixilon.minosoft.data.mappings.entities.villagers.VillagerProfession @@ -92,7 +93,7 @@ class VersionMapping { val entityMetaIndexMap: MutableMap = mutableMapOf() val entityRegistry: Registry = Registry() - val blockEntityRegistry: Registry = Registry() + val blockEntityTypeRegistry = BlockEntityTypeRegistry(this) val blockEntityMetaDataTypeRegistry: Registry = Registry() val containerTypeRegistry: Registry = Registry() @@ -173,6 +174,8 @@ class VersionMapping { containerTypeRegistry.initialize(pixlyzerData["container_types"]?.asJsonObject, this, ContainerType, alternative = DefaultRegistries.CONTAINER_TYPE_REGISTRY.forVersion(version)) gameEventRegistry.initialize(pixlyzerData["game_events"]?.asJsonObject, this, GameEvent, alternative = DefaultRegistries.GAME_EVENT_REGISTRY.forVersion(version)) + blockEntityTypeRegistry.initialize(pixlyzerData["block_entities"]?.asJsonObject, this, BlockEntityType) + soundEventRegistry.initialize(pixlyzerData["sound_events"]?.asJsonObject, this, SoundEvent) particleTypeRegistry.initialize(pixlyzerData["particles"]?.asJsonObject, this, ParticleType) materialRegistry.initialize(pixlyzerData["materials"]?.asJsonObject, this, Material) @@ -189,13 +192,14 @@ class VersionMapping { entityRegistry.initialize(pixlyzerData["entities"]?.asJsonObject, this, EntityType) - blockEntityRegistry.initialize(pixlyzerData["block_entities"]?.asJsonObject, this, BlockEntityType) blockEntityMetaDataTypeRegistry.initialize(pixlyzerData["block_entity_meta_data_types"]?.asJsonObject, this, BlockEntityMetaType, alternative = DefaultRegistries.BLOCK_ENTITY_META_TYPE_REGISTRY.forVersion(version)) // post init biomeRegistry.postInit(this) fluidRegistry.postInit(this) + blockEntityTypeRegistry.postInit(this) + blockRegistry.postInit(this) isFullyLoaded = true } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt index aa94d71d6..9ff372447 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt @@ -150,7 +150,7 @@ class BlockOutlineRenderer( } if (connection.player.entity.gamemode == Gamemodes.ADVENTURE || connection.player.entity.gamemode == Gamemodes.SPECTATOR) { - if (connection.mapping.blockEntityRegistry.get(raycastHit.blockState.block.resourceLocation) == null) { + if (raycastHit.blockState.block.blockEntityType == null) { unload() return } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockActionS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockActionS2CP.kt index 0e584f4ae..aa7ab5060 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockActionS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockActionS2CP.kt @@ -19,7 +19,6 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer import de.bixilon.minosoft.protocol.protocol.ProtocolVersions -import de.bixilon.minosoft.util.KUtil.asResourceLocation import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogMessageType @@ -36,20 +35,11 @@ class BlockActionS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { val block: Block = buffer.connection.mapping.blockRegistry.get(buffer.readVarInt()) override fun handle(connection: PlayConnection) { - val blockEntityTypeResourceLocation = when (block.resourceLocation.full) { - "minecraft:white_shulker_box", "minecraft:orange_shulker_box", "minecraft:magenta_shulker_box", "minecraft:light_blue_shulker_box", - "minecraft:yellow_shulker_box", "minecraft:lime_shulker_box", "minecraft:pink_shulker_box", "minecraft:gray_shulker_box", - "minecraft:silver_shulker_box", "minecraft:cyan_shulker_box", "minecraft:purple_shulker_box", "minecraft:blue_shulker_box", - "minecraft:brown_shulker_box", "minecraft:green_shulker_box", "minecraft:red_shulker_box", "minecraft:black_shulker_box", - -> "minecraft:shulker_box" - else -> block.resourceLocation.full - }.asResourceLocation() - val blockEntity = connection.world.getBlockEntity(position) ?: let { - val factory = connection.mapping.blockEntityRegistry.get(blockEntityTypeResourceLocation)?.factory - ?: DefaultBlockEntityMetaDataFactory.getEntityFactory(blockEntityTypeResourceLocation) + val factory = connection.mapping.blockEntityTypeRegistry[block.resourceLocation]?.factory + ?: DefaultBlockEntityMetaDataFactory.getEntityFactory(block.resourceLocation) ?: let { - Log.log(LogMessageType.NETWORK_PACKETS_IN, LogLevels.WARN) { "Unknown block entity $blockEntityTypeResourceLocation" } + Log.log(LogMessageType.NETWORK_PACKETS_IN, LogLevels.WARN) { "Unknown block entity ${block.resourceLocation}" } return } val blockEntity = factory.build(connection) diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt index 277567613..0fc0f5005 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt @@ -106,7 +106,7 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { val nbt = buffer.readNBT()?.compoundCast()!! val position = Vec3i(nbt["x"]?.nullCast()!!, nbt["y"]?.nullCast()!!, nbt["z"]?.nullCast()!!) val resourceLocation = ResourceLocation(nbt["id"]?.nullCast()!!) - val type = buffer.connection.mapping.blockEntityRegistry.get(resourceLocation) ?: let { + val type = buffer.connection.mapping.blockEntityTypeRegistry.get(resourceLocation) ?: let { Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.WARN) { "Unknown block entity: $resourceLocation" } null } ?: continue diff --git a/src/main/java/de/bixilon/minosoft/util/KUtil.kt b/src/main/java/de/bixilon/minosoft/util/KUtil.kt index 3aecc84be..20037d4fd 100644 --- a/src/main/java/de/bixilon/minosoft/util/KUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/KUtil.kt @@ -86,4 +86,14 @@ object KUtil { fun Set.toSynchronizedSet(): MutableSet { return synchronizedCopy { Collections.synchronizedSet(this.toMutableSet()) } } + + fun Set.toResourceLocationList(): Set { + val ret: MutableSet = mutableSetOf() + + for (resourceLocation in this) { + ret += resourceLocation.asResourceLocation() + } + + return ret.toSet() + } }