From 971ed120cf8f84a2128040dcf1d1d68be0cdd401 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Wed, 4 May 2022 19:45:00 +0200 Subject: [PATCH] mesher: improve (fluid) perpare speed --- .../data/registries/blocks/BlockState.kt | 2 +- .../de/bixilon/minosoft/data/world/Chunk.kt | 15 ++++--- .../rendering/models/SingleBlockRenderable.kt | 2 +- .../models/baked/MultipartBakedModel.kt | 4 +- .../models/baked/WeightedBakedModel.kt | 4 +- .../baked/block/BakedBlockStateModel.kt | 4 +- .../rendering/models/baked/block/BakedFace.kt | 2 +- .../renderer/sign/SignBlockEntityRenderer.kt | 2 +- .../preparer/cull/FluidCullSectionPreparer.kt | 39 ++++++++++++++----- .../preparer/cull/SolidCullSectionPreparer.kt | 5 +-- .../protocol/protocol/InByteBuffer.kt | 2 +- .../protocol/protocol/PlayInByteBuffer.kt | 1 - 12 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/BlockState.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/BlockState.kt index b9daff0ec..7333e4214 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/BlockState.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/BlockState.kt @@ -147,7 +147,7 @@ data class BlockState( fallSoundEvent = data["fall_sound_type"]?.toInt()?.let { registries.soundEventRegistry[it] }, soundEventVolume = data["sound_type_volume"]?.toFloat() ?: 1.0f, soundEventPitch = data["sound_type_pitch"]?.toFloat() ?: 1.0f, - isSolid = data["solid_render"]?.toBoolean() ?: true, // ToDo: This should normally be false, but pixlyzers default value is true. Might break if the data is missing + isSolid = data["solid_render"]?.toBoolean() ?: false, ) } diff --git a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt index 5e3a63fbb..e2c875124 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt @@ -73,7 +73,7 @@ class Chunk( operator fun get(position: Vec3i): BlockState? = get(position.x, position.y, position.z) fun set(x: Int, y: Int, z: Int, blockState: BlockState?, blockEntity: BlockEntity? = null) { - val section = getOrPut(y.sectionHeight) + val section = getOrPut(y.sectionHeight) ?: return section.blocks[x, y.inSectionHeight, z] = blockState section.blockEntities[x, y.inSectionHeight, z] = blockEntity // ToDo } @@ -103,7 +103,7 @@ class Chunk( return null } blockEntity = block.block.factory?.build(connection) ?: return null - this.getOrPut(sectionHeight).blockEntities[x, inSectionHeight, z] = blockEntity + (this.getOrPut(sectionHeight) ?: return null).blockEntities[x, inSectionHeight, z] = blockEntity return blockEntity } @@ -112,7 +112,7 @@ class Chunk( fun getOrPutBlockEntity(position: Vec3i): BlockEntity? = getOrPutBlockEntity(position.x, position.y, position.z) fun setBlockEntity(x: Int, y: Int, z: Int, blockEntity: BlockEntity?) { - getOrPut(y.sectionHeight).blockEntities[x, y.inSectionHeight, z] = blockEntity + (getOrPut(y.sectionHeight) ?: return).blockEntities[x, y.inSectionHeight, z] = blockEntity } fun setBlockEntity(position: Vec3i, blockEntity: BlockEntity?) = setBlockEntity(position.x, position.y, position.z, blockEntity) @@ -133,7 +133,7 @@ class Chunk( data.blocks?.let { for ((index, blocks) in it.withIndex()) { blocks ?: continue - val section = getOrPut(index + lowestSection) + val section = getOrPut(index + lowestSection) ?: return@let section.blocks = blocks } blocksInitialized = true @@ -146,7 +146,7 @@ class Chunk( data.light?.let { for ((index, light) in it.withIndex()) { light ?: continue - val section = getOrPut(index + lowestSection) + val section = getOrPut(index + lowestSection) ?: return@let section.light = light } lightInitialized = true @@ -170,9 +170,12 @@ class Chunk( } @Synchronized - private fun getOrPut(sectionHeight: Int): ChunkSection { + private fun getOrPut(sectionHeight: Int): ChunkSection? { val sections = sections ?: throw NullPointerException("Sections not initialized yet!") val sectionIndex = sectionHeight - lowestSection + if (sectionIndex < 0 || sectionIndex > sections.size) { + return null + } var section = sections[sectionIndex] if (section == null) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/SingleBlockRenderable.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/SingleBlockRenderable.kt index b5c7d9e1b..fdcf4c7fe 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/SingleBlockRenderable.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/SingleBlockRenderable.kt @@ -20,5 +20,5 @@ import java.util.* interface SingleBlockRenderable { - fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, ambientLight: FloatArray, tints: IntArray?): Boolean + fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt index bf7485419..cad860ff8 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt @@ -32,10 +32,10 @@ class MultipartBakedModel( return sizes[direction.ordinal] } - override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, ambientLight: FloatArray, tints: IntArray?): Boolean { + override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { var rendered = false for (model in models) { - if (model.singleRender(position, mesh, random, blockState, neighbours, light, ambientLight, tints) && !rendered) { + if (model.singleRender(position, mesh, random, blockState, neighbours, light, tints) && !rendered) { rendered = true } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt index 1490b4cf1..fd0c83426 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt @@ -58,8 +58,8 @@ class WeightedBakedModel( throw IllegalStateException("Could not find a model: This should never happen!") } - override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, ambientLight: FloatArray, tints: IntArray?): Boolean { - return getModel(random)?.singleRender(position, mesh, random, blockState, neighbours, light, ambientLight, tints) ?: false + override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { + return getModel(random)?.singleRender(position, mesh, random, blockState, neighbours, light, tints) ?: false } override fun getParticleTexture(random: Random, blockPosition: Vec3i): AbstractTexture? { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt index 2fffa5043..334141898 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt @@ -36,7 +36,7 @@ class BakedBlockStateModel( return touchingFaceProperties[direction.ordinal] } - override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, ambientLight: FloatArray, tints: IntArray?): Boolean { + override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { val floatPosition = position.toVec3() blockState.block.randomOffsetType?.let { floatPosition += position.getWorldOffset(blockState.block) @@ -68,7 +68,7 @@ class BakedBlockStateModel( } tint = tints?.getOrNull(face.tintIndex) ?: -1 currentLight = (face.cullFace?.let { light[it.ordinal] } ?: light[SolidCullSectionPreparer.SELF_LIGHT_INDEX]).toInt() - face.singleRender(positionArray, mesh, currentLight, ambientLight, tint) + face.singleRender(positionArray, mesh, currentLight, tint) if (!rendered) { rendered = true } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt index dad4e1a7a..eb8082cd0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt @@ -38,7 +38,7 @@ class BakedFace( override val transparency: TextureTransparencies get() = texture.transparency // ToDo - fun singleRender(position: FloatArray, mesh: WorldMesh, light: Int, ambientLight: FloatArray, tint: Int) { + fun singleRender(position: FloatArray, mesh: WorldMesh, light: Int, tint: Int) { val meshToUse = transparency.getMesh(mesh) // ToDo: Ambient light val color = Vec3(shade) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt index 68a69de1e..c49e1d5bd 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt @@ -45,7 +45,7 @@ class SignBlockEntityRenderer( override val blockState: BlockState, ) : OnlyMeshedBlockEntityRenderer { - override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, ambientLight: FloatArray, tints: IntArray?): Boolean { + override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { val block = this.blockState.block if (block is StandingSignBlock) { renderStandingText(position, mesh, light[SolidCullSectionPreparer.SELF_LIGHT_INDEX].toInt()) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt index 9d2a85321..b2240dc69 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt @@ -37,6 +37,8 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparenci import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.getMesh import de.bixilon.minosoft.gui.rendering.util.VecUtil +import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition +import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rotate @@ -128,10 +130,10 @@ class FluidCullSectionPreparer( } val cornerHeights = floatArrayOf( - getCornerHeight(position, fluid), - getCornerHeight(position + Directions.EAST, fluid), - getCornerHeight(position + Directions.EAST + Directions.SOUTH, fluid), - getCornerHeight(position + Directions.SOUTH, fluid), + getCornerHeight(chunk, chunkPosition, position, fluid), + getCornerHeight(chunk, chunkPosition, position + Directions.EAST, fluid), + getCornerHeight(chunk, chunkPosition, position + Directions.EAST + Directions.SOUTH, fluid), + getCornerHeight(chunk, chunkPosition, position + Directions.SOUTH, fluid), ) if (!skip[Directions.O_UP]) { @@ -262,21 +264,38 @@ class FluidCullSectionPreparer( neighbours.release() } - private fun getCornerHeight(position: Vec3i, fluid: Fluid): Float { - // ToDo: Optimize + private fun getCornerHeight(providedChunk: Chunk, providedChunkPosition: Vec2i, position: Vec3i, fluid: Fluid): Float { + // ToDo: Optimize more var totalHeight = 0.0f var count = 0 + var lastChunkPosition = providedChunkPosition + var lastChunk: Chunk? = providedChunk + for (side in 0 until 4) { val blockPosition = position + Vec3i(-(side and 0x01), 0, -(side shr 1 and 0x01)) - if (fluid.matches(world[blockPosition + Directions.UP])) { + val chunkPosition = blockPosition.chunkPosition + if (chunkPosition != lastChunkPosition) { + lastChunkPosition = chunkPosition + lastChunk = world[chunkPosition] + } + if (lastChunk == null) { + count++ + continue + } + val inChunkPosition = blockPosition.inChunkPosition + if (fluid.matches(lastChunk[inChunkPosition + Directions.UP])) { return 1.0f } - val blockState = world[blockPosition] + val blockState = lastChunk[inChunkPosition] + if (blockState == null) { + count++ + continue + } - if (blockState == null || !fluid.matches(blockState)) { - if (blockState?.material?.solid != true) { + if (!fluid.matches(blockState)) { + if (!blockState.material.solid) { count++ } continue diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt index 118b9e16c..c7a29da4b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt @@ -49,7 +49,6 @@ class SolidCullSectionPreparer( private val bedrock = renderWindow.connection.registries.blockRegistry[MinecraftBlocks.BEDROCK]?.defaultState private val someFullBlock = renderWindow.connection.registries.blockRegistry[MinecraftBlocks.COMMAND_BLOCK]?.defaultState private val tintColorCalculator = renderWindow.tintManager - private val ambientLight = floatArrayOf(1.0f, 1.0f, 1.0f, 1.0f) private var fastBedrock = false init { @@ -167,10 +166,10 @@ class SolidCullSectionPreparer( random.setSeed(0L) } tints = tintColorCalculator.getAverageTint(chunk, neighbourChunks, blockState, x, y, z) - rendered = model.singleRender(position, mesh, random, blockState, neighbourBlocks, light, ambientLight, tints) + rendered = model.singleRender(position, mesh, random, blockState, neighbourBlocks, light, tints) if (blockEntityModel is MeshedBlockEntityRenderer<*>) { - rendered = blockEntityModel.singleRender(position, mesh, random, blockState, neighbourBlocks, light, ambientLight, tints) || rendered + rendered = blockEntityModel.singleRender(position, mesh, random, blockState, neighbourBlocks, light, tints) || rendered } if (rendered) { diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt index 620e1c011..524a8368e 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt @@ -420,7 +420,7 @@ open class InByteBuffer { return Pair(resourceLocation, Tag(items.toSet())) } - @Deprecated("Use readArray") + @Deprecated("Use readArray", ReplaceWith("mapOf(*(readArray(length) { readTag(idResolver) }))")) fun readTagArray(length: Int = readVarInt(), idResolver: (Int) -> T): Map> { return mapOf(*(readArray(length) { readTag(idResolver) })) } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt b/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt index ce17ad3ae..a6d75b17d 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt @@ -217,7 +217,6 @@ class PlayInByteBuffer : InByteBuffer { return readArray(length) { readEntityId() } } - fun readPlayerProperties(): PlayerProperties { var textures: PlayerTextures? = null for (i in 0 until readVarInt()) {