count FluidFillable blocks as fluid, restructure some fluid stuff

This commit is contained in:
Bixilon 2021-11-22 18:40:21 +01:00
parent 1fdb1b6403
commit 5fc6b606bb
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 128 additions and 75 deletions

View File

@ -13,8 +13,8 @@
package de.bixilon.minosoft.data.registries.blocks.types
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.fluid.Fluid
interface FluidFillable {
val fluid: ResourceLocation
val fluid: Fluid
}

View File

@ -1,7 +1,9 @@
package de.bixilon.minosoft.data.world.container
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
import de.bixilon.minosoft.data.registries.blocks.types.FluidFillable
import de.bixilon.minosoft.util.KUtil.unsafeCast
class BlockSectionDataProvider(
@ -16,7 +18,7 @@ class BlockSectionDataProvider(
fluidCount = 0
for (blockState in data) {
if (blockState?.block is FluidBlock) {
if (blockState.isFluid()) {
fluidCount++
}
}
@ -24,13 +26,29 @@ class BlockSectionDataProvider(
override fun set(index: Int, value: BlockState?): BlockState? {
val previous = super.set(index, value)
val previousFluid = previous.isFluid()
val valueFluid = value.isFluid()
if (previous?.block !is FluidBlock && value?.block is FluidBlock) {
if (!previousFluid && valueFluid) {
fluidCount++
} else if (previous?.block is FluidBlock && value?.block !is FluidBlock) {
} else if (previousFluid && !valueFluid) {
fluidCount--
}
return previous
}
private fun BlockState?.isFluid(): Boolean {
this ?: return false
if (this.block is FluidBlock) {
return true
}
if (properties[BlockProperties.WATERLOGGED] == true) {
return true
}
if (this.block is FluidFillable) {
return true
}
return false
}
}

View File

@ -49,8 +49,10 @@ import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
import de.bixilon.minosoft.gui.rendering.world.mesh.SectionMesh
import de.bixilon.minosoft.gui.rendering.world.mesh.VisibleMeshes
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
import de.bixilon.minosoft.gui.rendering.world.preparer.AbstractSectionPreparer
import de.bixilon.minosoft.gui.rendering.world.preparer.CullSectionPreparer
import de.bixilon.minosoft.gui.rendering.world.preparer.FluidSectionPreparer
import de.bixilon.minosoft.gui.rendering.world.preparer.SolidSectionPreparer
import de.bixilon.minosoft.gui.rendering.world.preparer.cull.FluidCullSectionPreparer
import de.bixilon.minosoft.gui.rendering.world.preparer.cull.SolidCullSectionPreparer
import de.bixilon.minosoft.modding.event.events.*
import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionStateChangeEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
@ -84,7 +86,8 @@ class WorldRenderer(
private val shader = renderSystem.createShader("minosoft:world".toResourceLocation())
private val transparentShader = renderSystem.createShader("minosoft:world".toResourceLocation())
private val world: World = connection.world
private val sectionPreparer: AbstractSectionPreparer = CullSectionPreparer(renderWindow)
private val solidSectionPreparer: SolidSectionPreparer = SolidCullSectionPreparer(renderWindow)
private val fluidSectionPreparer: FluidSectionPreparer = FluidCullSectionPreparer(renderWindow)
private val lightMap = LightMap(connection)
private val loadedMeshes: MutableMap<Vec2i, MutableMap<Int, SectionMesh>> = mutableMapOf() // all prepared (and up to date) meshes
@ -106,8 +109,8 @@ class WorldRenderer(
// all meshes that will be rendered in the next frame (might be changed, when the frustum changes or a chunk gets loaded, ...)
private var clearVisibleNextFrame = false
private var visibleSolid = VisibleMeshes()
private var visibleFluid = VisibleMeshes()
private var visibleSolid = VisibleMeshes() // This name might be confusing. Those faces are from blocks.
private var visibleFluid = VisibleMeshes() // Fluids disable FACE_CULLING. Blocks that have waterlogged=true also twice
private var cameraPosition = Vec3.EMPTY
@ -354,9 +357,9 @@ class WorldRenderer(
val section = chunk[item.sectionHeight] ?: return@Runnable end()
val neighbourChunks: Array<Chunk> = world.getChunkNeighbours(item.chunkPosition).unsafeCast()
val neighbours = item.neighbours ?: ChunkUtil.getSectionNeighbours(neighbourChunks, chunk, item.sectionHeight)
item.solidMesh = sectionPreparer.prepareSolid(item.chunkPosition, item.sectionHeight, chunk, section, neighbours, neighbourChunks)
item.solidMesh = solidSectionPreparer.prepareSolid(item.chunkPosition, item.sectionHeight, chunk, section, neighbours, neighbourChunks)
if (section.blocks.fluidCount > 0) {
item.fluidMesh = sectionPreparer.prepareFluid(item.chunkPosition, item.sectionHeight, chunk, section, neighbours, neighbourChunks)
item.fluidMesh = fluidSectionPreparer.prepareFluid(item.chunkPosition, item.sectionHeight, chunk, section, neighbours, neighbourChunks)
}
meshesToLoadLock.lock()
locked = true

View File

@ -5,9 +5,7 @@ import de.bixilon.minosoft.data.world.ChunkSection
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
import glm_.vec2.Vec2i
interface AbstractSectionPreparer {
fun prepareSolid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbours: Array<ChunkSection?>, neighbourChunks: Array<Chunk>): WorldMesh?
interface FluidSectionPreparer {
fun prepareFluid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbours: Array<ChunkSection?>, neighbourChunks: Array<Chunk>): WorldMesh?
}

View File

@ -31,7 +31,7 @@ import java.util.*
@Deprecated("TODO")
class GreedySectionPreparer(
val renderWindow: RenderWindow,
) : AbstractSectionPreparer {
) : SolidSectionPreparer {
private fun renderNormal(block: BlockState, directions: Directions?, position: Vec3i, section: ChunkSection, mesh: SingleWorldMesh, random: Random) {
val neighbour = section.blocks[ChunkSection.getIndex(position.x, position.y, position.z)]
@ -235,8 +235,4 @@ class GreedySectionPreparer(
TODO()
}
override fun prepareFluid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbours: Array<ChunkSection?>, neighbourChunks: Array<Chunk>): WorldMesh? {
TODO("Not yet implemented")
}
}

View File

@ -0,0 +1,11 @@
package de.bixilon.minosoft.gui.rendering.world.preparer
import de.bixilon.minosoft.data.world.Chunk
import de.bixilon.minosoft.data.world.ChunkSection
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
import glm_.vec2.Vec2i
interface SolidSectionPreparer {
fun prepareSolid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbours: Array<ChunkSection?>, neighbourChunks: Array<Chunk>): WorldMesh?
}

View File

@ -0,0 +1,78 @@
package de.bixilon.minosoft.gui.rendering.world.preparer.cull
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
import de.bixilon.minosoft.data.registries.blocks.types.FluidFillable
import de.bixilon.minosoft.data.registries.fluid.DefaultFluids
import de.bixilon.minosoft.data.world.Chunk
import de.bixilon.minosoft.data.world.ChunkSection
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
import de.bixilon.minosoft.gui.rendering.world.preparer.FluidSectionPreparer
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.chunk.ChunkUtil.acquire
import de.bixilon.minosoft.util.chunk.ChunkUtil.release
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
import glm_.vec2.Vec2i
import glm_.vec3.Vec3i
class FluidCullSectionPreparer(
val renderWindow: RenderWindow,
) : FluidSectionPreparer {
private val water = renderWindow.connection.registries.fluidRegistry[DefaultFluids.WATER]
private val tintColorCalculator = renderWindow.tintManager
override fun prepareFluid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbours: Array<ChunkSection?>, neighbourChunks: Array<Chunk>): WorldMesh? {
val mesh = WorldMesh(renderWindow, chunkPosition, sectionHeight, smallMesh = true)
val isLowestSection = sectionHeight == chunk.lowestSection
val isHighestSection = sectionHeight == chunk.highestSection
val blocks = section.blocks
val sectionLight = section.light
section.acquire()
neighbours.acquire()
var blockState: BlockState
var position: Vec3i
var rendered = false
var tints: IntArray?
val offsetX = chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X
val offsetY = sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y
val offsetZ = chunkPosition.y * ProtocolDefinition.SECTION_WIDTH_Z
for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
for (y in 0 until ProtocolDefinition.SECTION_HEIGHT_Y) {
for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
blockState = blocks.unsafeGet(x, y, z) ?: continue
val block = blockState.block
val fluid = when {
block is FluidBlock -> (blockState.block as FluidBlock).fluid
blockState.properties[BlockProperties.WATERLOGGED] == true && water != null -> water
block is FluidFillable -> block.fluid
else -> continue
}
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Can not render fluid: $fluid" }
if (rendered) {
mesh.addBlock(x, y, z)
}
}
}
}
section.release()
neighbours.release()
if (mesh.clearEmpty() == 0) {
return null
}
return mesh
}
}

View File

@ -1,4 +1,4 @@
package de.bixilon.minosoft.gui.rendering.world.preparer
package de.bixilon.minosoft.gui.rendering.world.preparer.cull
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.direction.Directions.Companion.O_DOWN
@ -8,29 +8,24 @@ import de.bixilon.minosoft.data.direction.Directions.Companion.O_SOUTH
import de.bixilon.minosoft.data.direction.Directions.Companion.O_UP
import de.bixilon.minosoft.data.direction.Directions.Companion.O_WEST
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
import de.bixilon.minosoft.data.registries.fluid.DefaultFluids
import de.bixilon.minosoft.data.world.Chunk
import de.bixilon.minosoft.data.world.ChunkSection
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
import de.bixilon.minosoft.gui.rendering.util.VecUtil
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
import de.bixilon.minosoft.gui.rendering.world.preparer.SolidSectionPreparer
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.chunk.ChunkUtil.acquire
import de.bixilon.minosoft.util.chunk.ChunkUtil.release
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
import glm_.vec2.Vec2i
import glm_.vec3.Vec3i
import java.util.*
class CullSectionPreparer(
class SolidCullSectionPreparer(
val renderWindow: RenderWindow,
) : AbstractSectionPreparer {
private val water = renderWindow.connection.registries.fluidRegistry[DefaultFluids.WATER]
) : SolidSectionPreparer {
private val tintColorCalculator = renderWindow.tintManager
private val ambientLight = floatArrayOf(1.0f, 1.0f, 1.0f, 1.0f)
@ -141,50 +136,4 @@ class CullSectionPreparer(
return mesh
}
override fun prepareFluid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbours: Array<ChunkSection?>, neighbourChunks: Array<Chunk>): WorldMesh? {
val mesh = WorldMesh(renderWindow, chunkPosition, sectionHeight, smallMesh = true)
val isLowestSection = sectionHeight == chunk.lowestSection
val isHighestSection = sectionHeight == chunk.highestSection
val blocks = section.blocks
val sectionLight = section.light
section.acquire()
neighbours.acquire()
var blockState: BlockState
var position: Vec3i
var rendered = false
var tints: IntArray?
val offsetX = chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X
val offsetY = sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y
val offsetZ = chunkPosition.y * ProtocolDefinition.SECTION_WIDTH_Z
for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
for (y in 0 until ProtocolDefinition.SECTION_HEIGHT_Y) {
for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
blockState = blocks.unsafeGet(x, y, z) ?: continue
val fluid = when {
blockState.block is FluidBlock -> (blockState.block as FluidBlock).fluid
blockState.properties[BlockProperties.WATERLOGGED] == true && water != null -> water
else -> continue
}
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Can not render fluid: $fluid" }
if (rendered) {
mesh.addBlock(x, y, z)
}
}
}
}
section.release()
neighbours.release()
if (mesh.clearEmpty() == 0) {
return null
}
return mesh
}
}