From 96cc44c592b1e24c949222fd6c63e5eb659da406 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 6 Sep 2023 00:20:29 +0700 Subject: [PATCH] Fixed render regions actually being repeated for wrapped around chunks --- .../kstarbound/client/ClientWorld.kt | 36 ++++++++++++++++--- .../kstarbound/world/CoordinateMapper.kt | 30 ++++++++-------- .../ru/dbotthepony/kstarbound/world/World.kt | 4 +-- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientWorld.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientWorld.kt index d2dc7fda..38b78149 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientWorld.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientWorld.kt @@ -18,6 +18,7 @@ import ru.dbotthepony.kstarbound.world.api.ITileAccess import ru.dbotthepony.kstarbound.world.api.OffsetCellAccess import ru.dbotthepony.kstarbound.world.api.TileView import ru.dbotthepony.kstarbound.world.entities.Entity +import ru.dbotthepony.kstarbound.world.positiveModulo import ru.dbotthepony.kvector.api.IStruct2i import ru.dbotthepony.kvector.util2d.AABB import ru.dbotthepony.kvector.vector.RGBAColor @@ -47,6 +48,24 @@ class ClientWorld( val renderRegionWidth = if (size == null) 16 else determineChunkSize(size.x) val renderRegionHeight = if (size == null) 16 else determineChunkSize(size.y) + val renderRegionsX = if (size == null) 0 else size.x / renderRegionWidth + val renderRegionsY = if (size == null) 0 else size.y / renderRegionHeight + + fun isValidRenderRegionX(value: Int): Boolean { + if (size == null || loopX) { + return true + } else { + return value in 0 .. renderRegionsX + } + } + + fun isValidRenderRegionY(value: Int): Boolean { + if (size == null || loopY) { + return true + } else { + return value in 0 .. renderRegionsY + } + } inner class RenderRegion(val x: Int, val y: Int) { inner class Layer(private val view: ITileAccess, private val isBackground: Boolean) { @@ -170,6 +189,14 @@ class ClientWorld( val renderRegions = Long2ObjectOpenHashMap() + fun renderRegionKey(x: Int, y: Int): Long { + if (size == null) { + return x.toLong() shl 32 or y.toLong() + } else { + return positiveModulo(x, renderRegionsX).toLong() shl 32 or positiveModulo(y, renderRegionsY).toLong() + } + } + /** * all intersecting chunks */ @@ -180,7 +207,7 @@ class ClientWorld( for (x in ix .. ix + CHUNK_SIZE / renderRegionWidth) { for (y in iy .. iy + CHUNK_SIZE / renderRegionWidth) { - renderRegions[x.toLong() shl 32 or y.toLong()]?.let(action) + renderRegions[renderRegionKey(x, y)]?.let(action) } } } @@ -198,7 +225,7 @@ class ClientWorld( for ((x, y) in ring) { val ix = (pos.component1() + x) / renderRegionWidth val iy = (pos.component2() + y) / renderRegionHeight - val index = ix.toLong() shl 32 or iy.toLong() + val index = renderRegionKey(ix, iy) if (seen.add(index)) { renderRegions[index]?.let(action) @@ -207,7 +234,7 @@ class ClientWorld( } else { val ix = pos.component1() / renderRegionWidth val iy = pos.component2() / renderRegionHeight - renderRegions[ix.toLong() shl 32 or iy.toLong()]?.let(action) + renderRegions[renderRegionKey(ix, iy)]?.let(action) } } @@ -227,7 +254,8 @@ class ClientWorld( for (x in rx .. rx + dx) { for (y in ry .. ry + dy) { - val renderer = renderRegions.computeIfAbsent(x.toLong() shl 32 or y.toLong(), Long2ObjectFunction { + if (!isValidRenderRegionX(x) || !isValidRenderRegionY(y)) continue + val renderer = renderRegions.computeIfAbsent(renderRegionKey(x, y), Long2ObjectFunction { RenderRegion((it ushr 32).toInt(), it.toInt()) }) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/CoordinateMapper.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/CoordinateMapper.kt index 9ba4a7d6..b5d0af82 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/CoordinateMapper.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/CoordinateMapper.kt @@ -2,22 +2,22 @@ package ru.dbotthepony.kstarbound.world import ru.dbotthepony.kstarbound.math.divideUp +fun positiveModulo(a: Int, b: Int): Int { + val result = a % b + return if (result < 0) result + b else result +} + +fun positiveModulo(a: Double, b: Int): Double { + val result = a % b + return if (result < 0.0) result + b else result +} + +fun positiveModulo(a: Float, b: Int): Float { + val result = a % b + return if (result < 0f) result + b else result +} + abstract class CoordinateMapper { - protected fun positiveModulo(a: Int, b: Int): Int { - val result = a % b - return if (result < 0) result + b else result - } - - protected fun positiveModulo(a: Double, b: Int): Double { - val result = a % b - return if (result < 0.0) result + b else result - } - - protected fun positiveModulo(a: Float, b: Int): Float { - val result = a % b - return if (result < 0f) result + b else result - } - abstract val chunks: Int abstract fun cell(value: Int): Int diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt index 9b84a1c4..74259374 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt @@ -37,8 +37,8 @@ const val CHUNK_SIZEd = CHUNK_SIZE.toDouble() abstract class World, ChunkType : Chunk>( val seed: Long, val size: Vector2i?, - loopX: Boolean, - loopY: Boolean + val loopX: Boolean, + val loopY: Boolean ) : ICellAccess { val x: CoordinateMapper = if (size == null) CoordinateMapper.Infinite else if (loopX) CoordinateMapper.Wrapper(size.x) else CoordinateMapper.Clamper(size.x) val y: CoordinateMapper = if (size == null) CoordinateMapper.Infinite else if (loopY) CoordinateMapper.Wrapper(size.y) else CoordinateMapper.Clamper(size.y)