store block entity type in block

This commit is contained in:
Bixilon 2021-05-16 19:06:27 +02:00
parent 93dc93eea7
commit fc04dc9235
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
12 changed files with 134 additions and 28 deletions

View File

@ -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()

View File

@ -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<ShulkerBoxBlockEntity> {
companion object : BlockEntityFactory<ShulkerBoxBlockEntity>, MultiResourceLocationAble {
override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("minecraft:shulker_box")
override val ALIASES: Set<ResourceLocation> = 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)

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings
interface MultiResourceLocationAble {
val ALIASES: Set<ResourceLocation>
}

View File

@ -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<BlockLikeRenderer>? = 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 {

View File

@ -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<Int>?,
val factory: BlockEntityFactory<out BlockEntity>,
) : RegistryItem {
lateinit var blocks: Set<Block>
private set
override fun postInit(versionMapping: VersionMapping) {
val blocks: MutableSet<Block> = 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<Int> = mutableSetOf()
for (blockId in data["blocks"].asJsonArray) {
blockIds += blockId.asInt
}
return BlockEntityType(
resourceLocation = resourceLocation,
blockIds = blockIds,
factory = factory,
)
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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<BlockEntityType>() {
private lateinit var blockTypeMap: MutableMap<Block, BlockEntityType>
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
}
}
}
}

View File

@ -23,20 +23,20 @@ open class Registry<T : RegistryItem>(
private var parentRegistry: Registry<T>? = null,
) : Iterable<T>, Clearable, Parentable<Registry<T>> {
private var initialized = false
private val idValueMap: MutableMap<Int, T> = mutableMapOf()
private val valueIdMap: MutableMap<T, Int> = mutableMapOf()
private val resourceLocationMap: MutableMap<ResourceLocation, T> = mutableMapOf()
protected val idValueMap: MutableMap<Int, T> = mutableMapOf()
protected val valueIdMap: MutableMap<T, Int> = mutableMapOf()
protected val resourceLocationMap: MutableMap<ResourceLocation, T> = 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<T : RegistryItem>(
}
fun postInit(versionMapping: VersionMapping) {
open fun postInit(versionMapping: VersionMapping) {
for ((_, value) in resourceLocationMap) {
value.postInit(versionMapping)
}

View File

@ -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<EntityMetaDataFields, Int> = mutableMapOf()
val entityRegistry: Registry<EntityType> = Registry()
val blockEntityRegistry: Registry<BlockEntityType> = Registry()
val blockEntityTypeRegistry = BlockEntityTypeRegistry(this)
val blockEntityMetaDataTypeRegistry: Registry<BlockEntityMetaType> = Registry()
val containerTypeRegistry: Registry<ContainerType> = 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
}

View File

@ -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
}

View File

@ -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)

View File

@ -106,7 +106,7 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
val nbt = buffer.readNBT()?.compoundCast()!!
val position = Vec3i(nbt["x"]?.nullCast<Int>()!!, nbt["y"]?.nullCast<Int>()!!, nbt["z"]?.nullCast<Int>()!!)
val resourceLocation = ResourceLocation(nbt["id"]?.nullCast<String>()!!)
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

View File

@ -86,4 +86,14 @@ object KUtil {
fun <V> Set<V>.toSynchronizedSet(): MutableSet<V> {
return synchronizedCopy { Collections.synchronizedSet(this.toMutableSet()) }
}
fun Set<String>.toResourceLocationList(): Set<ResourceLocation> {
val ret: MutableSet<ResourceLocation> = mutableSetOf()
for (resourceLocation in this) {
ret += resourceLocation.asResourceLocation()
}
return ret.toSet()
}
}