world renderer: properly unload if empty

This commit is contained in:
Bixilon 2022-12-23 17:27:20 +01:00
parent 3988407c90
commit 072efe15eb
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 65 additions and 42 deletions

View File

@ -31,12 +31,12 @@ class ChunkMesher(
private fun mesh(item: WorldQueueItem): WorldMesh? {
if (item.section.blocks.isEmpty) {
renderer.queueItemUnload(item)
renderer.unload(item)
return null
}
val neighbours = item.chunk.neighbours.get()
if (neighbours == null) {
renderer.queueItemUnload(item)
renderer.unload(item)
return null
}
val sectionNeighbours = ChunkUtil.getDirectNeighbours(neighbours, item.chunk, item.section.sectionHeight)
@ -55,7 +55,7 @@ class ChunkMesher(
runnable.interruptable = false
if (Thread.interrupted()) return
if (mesh.clearEmpty() == 0) {
return renderer.queueItemUnload(item)
return renderer.unload(item)
}
mesh.finish()
item.mesh = mesh

View File

@ -19,6 +19,7 @@ import de.bixilon.kotlinglm.vec3.Vec3i
import de.bixilon.minosoft.data.world.chunk.Chunk
import de.bixilon.minosoft.data.world.chunk.ChunkSection
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
import de.bixilon.minosoft.gui.rendering.world.queue.QueuePosition
import java.util.*
class WorldQueueItem(
@ -32,11 +33,13 @@ class WorldQueueItem(
var mesh: WorldMesh? = null
override fun equals(other: Any?): Boolean {
if (other !is WorldQueueItem) {
return false
if (other is WorldQueueItem) {
return chunkPosition == other.chunkPosition && sectionHeight == other.sectionHeight
}
return chunkPosition == other.chunkPosition && sectionHeight == other.sectionHeight
if (other is QueuePosition) {
return chunkPosition == other.position && sectionHeight == other.sectionHeight
}
return false
}
override fun hashCode(): Int {

View File

@ -39,6 +39,7 @@ import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.blockPosition
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.chunkPosition
import de.bixilon.minosoft.gui.rendering.world.mesh.VisibleMeshes
import de.bixilon.minosoft.gui.rendering.world.queue.CulledQueue
import de.bixilon.minosoft.gui.rendering.world.queue.QueuePosition
import de.bixilon.minosoft.gui.rendering.world.queue.loading.MeshLoadingQueue
import de.bixilon.minosoft.gui.rendering.world.queue.loading.MeshUnloadingQueue
import de.bixilon.minosoft.gui.rendering.world.queue.meshing.ChunkMeshingQueue
@ -189,18 +190,15 @@ class WorldRenderer(
}
fun queueItemUnload(item: WorldQueueItem) {
fun unload(item: WorldQueueItem) = unload(QueuePosition(item.chunkPosition, item.sectionHeight))
fun unload(position: QueuePosition) {
lock.lock()
loaded.unload(item.chunkPosition, item.sectionHeight, false)
culledQueue.remove(item.chunkPosition, item.sectionHeight, false)
meshingQueue.remove(item, false)
loadingQueue.abort(item.chunkPosition, false)
meshingQueue.tasks.interrupt(item.chunkPosition, item.sectionHeight)
loaded.unload(position.position, position.sectionHeight, false)
culledQueue.remove(position.position, position.sectionHeight, false)
meshingQueue.remove(position, false)
loadingQueue.abort(position.position, false)
meshingQueue.tasks.interrupt(position.position, position.sectionHeight)
lock.unlock()
}
@ -287,9 +285,9 @@ class WorldRenderer(
for ((chunk, sectionHeight) in nextQueue) {
val neighbours = chunk.neighbours.get() ?: continue
chunk.neighbours.get() ?: continue
val section = chunk[sectionHeight] ?: continue
master.tryQueue(section, force = true, chunk = chunk, neighbours = neighbours)
master.tryQueue(section, force = true, chunk = chunk)
}
if (sortQueue && nextQueue.isNotEmpty()) {

View File

@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.world.preparer.cull
import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.kotlinglm.vec3.Vec3i
import de.bixilon.kutil.exception.Broken
import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.direction.Directions.Companion.O_DOWN
@ -61,11 +60,6 @@ class SolidCullSectionPreparer(
override fun prepareSolid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbourChunks: Array<Chunk>, neighbours: Array<ChunkSection?>, mesh: WorldMesh) {
val random = Random(0L)
for (chunk in neighbourChunks) {
if (chunk == null || chunk.sections == null || chunk.light == null) {
Broken("null!!!")
}
}
val randomBlockModels = profile.antiMoirePattern
val isLowestSection = sectionHeight == chunk.minSection

View File

@ -14,12 +14,29 @@
package de.bixilon.minosoft.gui.rendering.world.queue
import de.bixilon.minosoft.data.world.positions.ChunkPosition
import de.bixilon.minosoft.gui.rendering.world.WorldQueueItem
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
import java.util.*
data class QueuePosition(
class QueuePosition(
val position: ChunkPosition,
val sectionHeight: Int,
) {
constructor(mesh: WorldMesh) : this(mesh.chunkPosition, mesh.sectionHeight)
override fun equals(other: Any?): Boolean {
if (other is WorldQueueItem) {
return position == other.chunkPosition && sectionHeight == other.sectionHeight
}
if (other is QueuePosition) {
return position == other.position && sectionHeight == other.sectionHeight
}
return false
}
override fun hashCode(): Int {
return Objects.hash(position, sectionHeight)
}
}

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft.gui.rendering.world.queue.meshing
import de.bixilon.kotlinglm.vec3.Vec3i
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
import de.bixilon.kutil.concurrent.pool.ThreadPool
import de.bixilon.kutil.concurrent.pool.ThreadPoolRunnable
@ -21,6 +22,7 @@ import de.bixilon.minosoft.data.world.positions.ChunkPosition
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.length2
import de.bixilon.minosoft.gui.rendering.world.WorldQueueItem
import de.bixilon.minosoft.gui.rendering.world.WorldRenderer
import de.bixilon.minosoft.gui.rendering.world.queue.QueuePosition
import de.bixilon.minosoft.gui.rendering.world.queue.meshing.tasks.MeshPrepareTask
import de.bixilon.minosoft.gui.rendering.world.queue.meshing.tasks.MeshPrepareTaskManager
import de.bixilon.minosoft.util.SystemInformation
@ -141,6 +143,15 @@ class ChunkMeshingQueue(
if (lock) unlock()
}
fun remove(position: QueuePosition, lock: Boolean) {
if (lock) lock()
// dirty hacking
if (this.set.unsafeCast<MutableSet<QueuePosition>>().remove(position)) {
this.queue.unsafeCast<MutableList<QueuePosition>>() -= position
}
if (lock) unlock()
}
fun queue(item: WorldQueueItem) {
lock()

View File

@ -24,16 +24,16 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
import de.bixilon.minosoft.gui.rendering.world.WorldQueueItem
import de.bixilon.minosoft.gui.rendering.world.WorldRenderer
import de.bixilon.minosoft.gui.rendering.world.queue.QueuePosition
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
class ChunkQueueMaster(
private val renderer: WorldRenderer,
) {
private fun queue(section: ChunkSection, chunk: Chunk, force: Boolean, neighbours: Array<Chunk>): Boolean {
private fun queue(section: ChunkSection, chunk: Chunk, force: Boolean): Boolean {
if (section.blocks.isEmpty) {
// TODO: unload
renderer.unload(QueuePosition(chunk.chunkPosition, section.sectionHeight))
return false
}
@ -50,27 +50,27 @@ class ChunkQueueMaster(
return false
}
fun tryQueue(section: ChunkSection, force: Boolean = false, chunk: Chunk? = null, neighbours: Array<Chunk>? = null) {
fun tryQueue(section: ChunkSection, force: Boolean = false, chunk: Chunk? = null) {
if (!canQueue()) return
val chunk = chunk ?: section.chunk ?: return
if (!chunk.isFullyLoaded) return
val neighbours = neighbours ?: chunk.neighbours.get() ?: return
chunk.neighbours.get() ?: return
if (queue(section, chunk, force, neighbours)) {
if (queue(section, chunk, force)) {
renderer.meshingQueue.sort()
renderer.meshingQueue.work()
}
}
fun tryQueue(chunk: Chunk, sectionHeight: SectionHeight, force: Boolean = false, neighbours: Array<Chunk>? = null) {
fun tryQueue(chunk: Chunk, sectionHeight: SectionHeight, force: Boolean = false) {
val section = chunk[sectionHeight] ?: return
tryQueue(section, force, chunk, neighbours)
tryQueue(section, force, chunk)
}
fun tryQueue(chunk: Chunk, ignoreLoaded: Boolean = false, force: Boolean = false) {
if (!canQueue() || !chunk.isFullyLoaded) return
val neighbours: Array<Chunk> = chunk.neighbours.get() ?: return
chunk.neighbours.get() ?: return
if (!ignoreLoaded && chunk.chunkPosition in renderer.loaded) {
// chunks only get queued when the server sends them, we normally do not want to queue them again.
@ -81,7 +81,7 @@ class ChunkQueueMaster(
var changes = 0
for (sectionHeight in chunk.minSection..chunk.maxSection) { // TODO .. or until?
val section = chunk[sectionHeight] ?: continue
if (queue(section, chunk, force, neighbours)) {
if (queue(section, chunk, force)) {
changes++
}
}

View File

@ -42,13 +42,13 @@ object WorldRendererChangeListener {
val chunk = renderer.world[chunkPosition] ?: return@listen
val neighbours = chunk.neighbours.get() ?: return@listen
master.tryQueue(chunk, sectionHeight, neighbours = neighbours)
master.tryQueue(chunk, sectionHeight)
val inPosition = it.blockPosition.inChunkSectionPosition
if (inPosition.y == 0) {
master.tryQueue(chunk, sectionHeight - 1, neighbours = neighbours)
master.tryQueue(chunk, sectionHeight - 1)
} else if (inPosition.y == ProtocolDefinition.SECTION_MAX_Y) {
master.tryQueue(chunk, sectionHeight + 1, neighbours = neighbours)
master.tryQueue(chunk, sectionHeight + 1)
}
if (inPosition.z == 0) {
master.tryQueue(chunk = neighbours[3], sectionHeight)
@ -92,13 +92,13 @@ object WorldRendererChangeListener {
}
val neighbours = chunk.neighbours.get() ?: return@listen
for ((sectionHeight, neighbourUpdates) in sectionHeights) {
master.tryQueue(chunk, sectionHeight, neighbours = neighbours)
master.tryQueue(chunk, sectionHeight)
if (neighbourUpdates[0]) {
master.tryQueue(chunk, sectionHeight - 1, neighbours = neighbours)
master.tryQueue(chunk, sectionHeight - 1)
}
if (neighbourUpdates[1]) {
master.tryQueue(chunk, sectionHeight + 1, neighbours = neighbours)
master.tryQueue(chunk, sectionHeight + 1)
}
if (neighbourUpdates[2]) {
master.tryQueue(neighbours[3], sectionHeight)