From f0af2d5a8e8e5455a8cbd5685c2400d6fdda7a4a Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 3 Feb 2022 11:00:29 +0700 Subject: [PATCH] =?UTF-8?q?=D0=9A=D0=B5=D1=88=20GLShaderProgram,=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B0=20=D0=BC=D0=B0=D1=82?= =?UTF-8?q?=D1=80=D0=B8=D1=86=20=D0=BD=D0=B0=D0=BF=D1=80=D1=8F=D0=BC=D1=83?= =?UTF-8?q?=D1=8E=20=D0=B2=20=D0=B2=D0=B8=D0=B4=D0=B5=D0=BE=D0=BF=D0=B0?= =?UTF-8?q?=D0=BC=D1=8F=D1=82=D1=8C,=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20TileDef?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/ru/dbotthepony/kstarbound/Main.kt | 78 +++--------- .../kstarbound/defs/TileDefinition.kt | 30 ++++- .../kstarbound/gl/GLShaderProgram.kt | 40 ++++++- .../ru/dbotthepony/kstarbound/math/Matrix.kt | 111 ++++++++++++++++++ .../ru/dbotthepony/kstarbound/world/Chunk.kt | 92 ++++++++++++--- .../ru/dbotthepony/kstarbound/world/World.kt | 19 ++- 6 files changed, 275 insertions(+), 95 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt index 088b608a..f28e6c95 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt @@ -138,48 +138,27 @@ private fun loop() { state.blend = true glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) - val rock = ChunkTile(Starbound.getTileDefinition("alienrock")!!) - val obsidian = ChunkTile(Starbound.getTileDefinition("obsidian")!!) - val corruptdirt = ChunkTile(Starbound.getTileDefinition("corruptdirt")!!) - val darkwood = ChunkTile(Starbound.getTileDefinition("darkwood")!!) - val chunk = Starbound.world.setTile(Vector2i(2, 2), rock) - - chunk[3, 2] = rock - chunk[4, 2] = rock - chunk[4, 3] = rock - chunk[4, 4] = rock - chunk[3, 4] = rock - chunk[5, 4] = rock - chunk[2, 4] = obsidian - chunk[2, 3] = obsidian - chunk[1, 4] = corruptdirt - chunk[1, 3] = corruptdirt - chunk[1, 5] = darkwood - chunk[2, 5] = darkwood - chunk[3, 5] = darkwood - chunk[1, 1] = darkwood - chunk[2, 1] = darkwood - chunk[3, 1] = darkwood - - for (x in 0 until 1) { - for (y in 0 until 4) { - //chunk[x, y] = ChunkTile(Starbound.loadTileDefinition("alienrock")) - } - } + val chunk = Starbound.world.getOrMakeChunk(Vector2i(2, 2)) var x = 0 var y = 0 for (tile in Starbound.tilesAccess.values) { - chunk[x++, y] = ChunkTile(tile) - chunk[x++, y] = ChunkTile(tile) - chunk[x++, y] = ChunkTile(tile) - chunk[x++, y] = ChunkTile(tile) - chunk[x++, y] = ChunkTile(tile) + chunk[x, y + 1] = (tile) + chunk[x++, y] = (tile) + chunk[x, y + 1] = (tile) + chunk[x++, y] = (tile) + chunk[x, y + 1] = (tile) + chunk[x++, y] = (tile) + chunk[x, y + 1] = (tile) + chunk[x++, y] = (tile) + chunk[x, y + 1] = (tile) + chunk[x++, y] = (tile) + chunk[x, y + 1] = (tile) - if (x >= 24) { + if (x >= 32) { x = 0 - y++ + y += 2 } } @@ -194,37 +173,8 @@ private fun loop() { state.matrixStack.clear(viewportMatrixGame.toMutableMatrix()) - // program.use() - - // val time = glfwGetTime() - // program["globalColor"] = Uniform3f(sin(time).toFloat(), cos(time).toFloat(), sin(time).toFloat()) - // program["ourTexture"] = 0 - - // texture.bind() - // vao.bind() - // ebo.bind() - // glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0) - // checkForGLError() - - //tileRenderer.renderPiece() - - //state.shaderVertexTexture.use() - //state.shaderVertexTexture["_texture"] = 0 - ////state.shaderVertexTexture["_transform"] = Vector3f.FORWARD.rotateAroundThis(PI * glfwGetTime()) - ////state.shaderVertexTexture["_transform"] = state.matrixStack.push().scale((glfwGetTime() % 1000.0).toFloat(), (glfwGetTime() % 1000.0).toFloat(), (glfwGetTime() % 1000.0).toFloat()).last - ////state.shaderVertexTexture["_transform"] = Matrix4f.perspective(((glfwGetTime() * 16.0) % 180.0).toFloat(), 0.1f, 100f) - //state.shaderVertexTexture["_transform"] = state.matrixStack.push().scale(x = 10f, y = 10f).translateWithScale(10f, 10f).last - //texture.bind() - //texture.textureMinFilter = GL_NEAREST - //texture.textureMagFilter = GL_NEAREST - //chunkRenderer.bind() - //glDrawElements(GL_TRIANGLES, chunkRenderer.indexCount, GL_UNSIGNED_INT, 0) - //checkForGLError() - state.matrixStack.push().scale(x = 20f, y = 20f).translateWithScale(0f, 0f) chunkRenderer.render() - //state.matrixStack.translateWithScale(18f) - //chunkRenderer.render() glfwSwapBuffers(window) // swap the color buffers diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/TileDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/TileDefinition.kt index 0e6ccb5c..bdd2ad60 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/TileDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/TileDefinition.kt @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableMap import com.google.gson.JsonArray import com.google.gson.JsonObject import com.google.gson.JsonPrimitive +import org.apache.logging.log4j.LogManager import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.math.Vector2i import ru.dbotthepony.kstarbound.util.Color @@ -18,6 +19,9 @@ data class TileDefinition( val itemDrop: String?, val description: String, val shortdescription: String, + val blocksLiquidFlow: Boolean, + val soil: Boolean, + val tillableMod: Int, val racialDescription: ImmutableMap, val footstepSound: String?, @@ -40,6 +44,10 @@ class TileDefinitionBuilder { var description = "..." var shortdescription = "..." + var blocksLiquidFlow = true + var soil = false + var tillableMod = 0 + val racialDescription = ArrayList>() var footstepSound: String? = null @@ -62,6 +70,9 @@ class TileDefinitionBuilder { itemDrop = itemDrop, description = description, shortdescription = shortdescription, + blocksLiquidFlow = blocksLiquidFlow, + soil = soil, + tillableMod = tillableMod, footstepSound = footstepSound, health = health, @@ -72,6 +83,8 @@ class TileDefinitionBuilder { } companion object { + private val LOGGER = LogManager.getLogger() + fun fromJson(input: JsonObject): TileDefinitionBuilder { val builder = TileDefinitionBuilder() @@ -83,12 +96,19 @@ class TileDefinitionBuilder { builder.particleColor = Color(input["particleColor"].asJsonArray) builder.itemDrop = input["itemDrop"]?.asString - builder.description = input["description"]?.asString ?: "..." - builder.shortdescription = input["shortdescription"]?.asString ?: "..." + builder.description = input["description"]?.asString ?: builder.description + builder.shortdescription = input["shortdescription"]?.asString ?: builder.shortdescription builder.footstepSound = input["footstepSound"]?.asString + builder.blocksLiquidFlow = input["footstepSound"]?.asBoolean ?: builder.blocksLiquidFlow + builder.soil = input["footstepSound"]?.asBoolean ?: builder.soil builder.health = input["health"].asInt + builder.tillableMod = input["health"]?.asInt ?: builder.tillableMod builder.category = input["category"].asString + if (input["variants"] != null) { + LOGGER.warn("Tile {} has `variants` ({}) defined as top level property (expected to be under `renderParameters`)", builder.materialName, input["variants"].asString) + } + for (key in input.keySet()) { if (key.endsWith("Description") && key.length != "Description".length) { builder.racialDescription.add(key.substring(0, key.length - "Description".length) to input[key].asString) @@ -98,9 +118,9 @@ class TileDefinitionBuilder { input["renderParameters"]?.asJsonObject?.let { builder.render.texture = it["texture"].asString builder.render.variants = it["variants"].asInt - builder.render.lightTransparent = it["lightTransparent"]?.asBoolean ?: false - builder.render.occludesBelow = it["occludesBelow"]?.asBoolean ?: true - builder.render.multiColored = it["multiColored"]?.asBoolean ?: false + builder.render.lightTransparent = it["lightTransparent"]?.asBoolean ?: builder.render.lightTransparent + builder.render.occludesBelow = it["occludesBelow"]?.asBoolean ?: builder.render.occludesBelow + builder.render.multiColored = it["multiColored"]?.asBoolean ?: builder.render.multiColored builder.render.zLevel = it["zLevel"].asInt } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/gl/GLShaderProgram.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/gl/GLShaderProgram.kt index 609c0496..20c78def 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/gl/GLShaderProgram.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/gl/GLShaderProgram.kt @@ -1,10 +1,16 @@ package ru.dbotthepony.kstarbound.gl +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap +import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import org.lwjgl.opengl.GL41 import org.lwjgl.opengl.GL46.* import ru.dbotthepony.kstarbound.api.IStruct3f import ru.dbotthepony.kstarbound.api.IStruct4F +import ru.dbotthepony.kstarbound.math.AbstractMatrix3f +import ru.dbotthepony.kstarbound.math.AbstractMatrix4f import ru.dbotthepony.kstarbound.math.FloatMatrix +import java.util.* +import kotlin.collections.HashSet class ShaderLinkException(reason: String) : RuntimeException(reason) @@ -37,11 +43,21 @@ class GLUniformLocation(val program: GLShaderProgram, val name: String, val poin if (value.rows == 3 && value.columns == 3) { // Матрица 3x3 - glProgramUniformMatrix3fv(program.pointer, pointer, false, value.toFloatArray()) + if (value is AbstractMatrix3f) { + glProgramUniformMatrix3fv(program.pointer, pointer, false, value.toFloatBuffer()) + } else { + glProgramUniformMatrix3fv(program.pointer, pointer, false, value.toFloatArray()) + } + checkForGLError() } else if (value.rows == 4 && value.columns == 4) { // Матрица 4x4 - glProgramUniformMatrix4fv(program.pointer, pointer, false, value.toFloatArray()) + if (value is AbstractMatrix4f) { + glProgramUniformMatrix4fv(program.pointer, pointer, false, value.toFloatBuffer()) + } else { + glProgramUniformMatrix4fv(program.pointer, pointer, false, value.toFloatArray()) + } + checkForGLError() } else { throw IllegalArgumentException("Can not use matrix with these dimensions: ${value.rows}x${value.columns}") @@ -59,16 +75,28 @@ class GLShaderProgram(val state: GLStateTracker, vararg shaders: GLShader) { private val attached = HashSet() val access = object : Collection by attached {} + private val locationCache = Object2ObjectArrayMap>() + + /** + * Возвращает GLUniformLocation или null, если у данной программы нет такого uniform + * + * В т.ч. если она была в коде шейдера, но нигде не использовалась (отсечена компилятором) + * + * Результат поиска кешируется, но для повышения производительности вызывающий код желательно так же + * должен кешировать результат (как локальное свойство или переменная, в случае многократного использования) + */ operator fun get(name: String): GLUniformLocation? { state.ensureSameThread() check(linked) { "Shader program is not linked!" } - val location = glGetUniformLocation(pointer, name) + return locationCache.computeIfAbsent(name, Object2ObjectFunction { + val location = glGetUniformLocation(pointer, name) - if (location == -1) - return null + if (location == -1) + return@Object2ObjectFunction Optional.empty() - return GLUniformLocation(this, name, location) + return@Object2ObjectFunction Optional.of(GLUniformLocation(this, name, location)) + }).orElse(null) } operator fun set(name: String, value: Uniform4f) = this[name]?.set(value) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/math/Matrix.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/math/Matrix.kt index a0d4fe62..143ceaa5 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/math/Matrix.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/math/Matrix.kt @@ -1,5 +1,8 @@ package ru.dbotthepony.kstarbound.math +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.nio.FloatBuffer import kotlin.math.PI import kotlin.math.tan @@ -74,6 +77,68 @@ interface MutableFloatMatrix> : FloatMatrix { } abstract class AbstractMatrix4f> : FloatMatrix { + companion object { + private val directBuffer by lazy { ByteBuffer.allocateDirect(4 * 4 * 4).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer()!! } + } + + /** + * Наполняет синглтон и возвращает DirectFloatBuffer который необходимо использовать сразу, + * нет никаких гарантий что он не будет изменён в дальнейшем + * + * Функция предназначена исключительно для загрузки данной матрицы в память видеокарты + * + * Данный буфер всегда будет одним и тем же, но его содержимое обновлено + */ + fun toFloatBuffer(columnMajor: Boolean = true): FloatBuffer { + val directBuffer = directBuffer + directBuffer.position(0) + + if (columnMajor) { + directBuffer.put(m00) + directBuffer.put(m10) + directBuffer.put(m20) + directBuffer.put(m30) + + directBuffer.put(m01) + directBuffer.put(m11) + directBuffer.put(m21) + directBuffer.put(m31) + + directBuffer.put(m02) + directBuffer.put(m12) + directBuffer.put(m22) + directBuffer.put(m32) + + directBuffer.put(m03) + directBuffer.put(m13) + directBuffer.put(m23) + directBuffer.put(m33) + } else { + directBuffer.put(m00) + directBuffer.put(m01) + directBuffer.put(m02) + directBuffer.put(m03) + + directBuffer.put(m10) + directBuffer.put(m11) + directBuffer.put(m12) + directBuffer.put(m13) + + directBuffer.put(m20) + directBuffer.put(m21) + directBuffer.put(m22) + directBuffer.put(m23) + + directBuffer.put(m30) + directBuffer.put(m31) + directBuffer.put(m32) + directBuffer.put(m33) + } + + directBuffer.position(0) + return directBuffer + } + abstract val m00: Float; abstract val m01: Float; abstract val m02: Float; abstract val m03: Float abstract val m10: Float; abstract val m11: Float; abstract val m12: Float; abstract val m13: Float abstract val m20: Float; abstract val m21: Float; abstract val m22: Float; abstract val m23: Float @@ -545,6 +610,52 @@ data class MutableMatrix4f( } abstract class AbstractMatrix3f> : FloatMatrix { + companion object { + private val directBuffer by lazy { ByteBuffer.allocateDirect(4 * 3 * 3).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer()!! } + } + + /** + * Наполняет синглтон и возвращает DirectFloatBuffer который необходимо использовать сразу, + * нет никаких гарантий что он не будет изменён в дальнейшем + * + * Функция предназначена исключительно для загрузки данной матрицы в память видеокарты + * + * Данный буфер всегда будет одним и тем же, но его содержимое обновлено + */ + fun toFloatBuffer(columnMajor: Boolean = true): FloatBuffer { + val directBuffer = directBuffer + directBuffer.position(0) + + if (columnMajor) { + directBuffer.put(m00) + directBuffer.put(m10) + directBuffer.put(m20) + + directBuffer.put(m01) + directBuffer.put(m11) + directBuffer.put(m21) + + directBuffer.put(m02) + directBuffer.put(m12) + directBuffer.put(m22) + } else { + directBuffer.put(m00) + directBuffer.put(m01) + directBuffer.put(m02) + + directBuffer.put(m10) + directBuffer.put(m11) + directBuffer.put(m12) + + directBuffer.put(m20) + directBuffer.put(m21) + directBuffer.put(m22) + } + + directBuffer.position(0) + return directBuffer + } + abstract val m00: Float; abstract val m01: Float; abstract val m02: Float abstract val m10: Float; abstract val m11: Float; abstract val m12: Float abstract val m20: Float; abstract val m21: Float; abstract val m22: Float diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/Chunk.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/Chunk.kt index 9a2d7bc7..120bdf36 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/Chunk.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/Chunk.kt @@ -1,12 +1,11 @@ package ru.dbotthepony.kstarbound.world -import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.defs.TileDefinition import ru.dbotthepony.kstarbound.math.Vector2i data class ChunkTile(val def: TileDefinition) { - companion object { - } + var color = -1 + var forceVariant = -1 } interface IChunk { @@ -16,8 +15,23 @@ interface IChunk { * Возвращает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка */ operator fun get(x: Int, y: Int): ChunkTile? + + /** + * Возвращает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка + */ operator fun get(pos: Vector2i) = get(pos.x, pos.y) + + /** + * Возвращает фоновый тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка + */ + fun getBackground(x: Int, y: Int): ChunkTile? + + /** + * Возвращает фоновый тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка + */ + fun getBackground(pos: Vector2i) = getBackground(pos.x, pos.y) + /** * Относительная проверка находится ли координата вне границ чагка */ @@ -39,7 +53,6 @@ interface IChunk { return long } - /** * Возвращает псевдослучайное нормализированное Double для заданной позиции * @@ -49,7 +62,6 @@ interface IChunk { return (randomLongFor(x, y) / 9.223372036854776E18) / 2.0 + 0.5 } - /** * Возвращает псевдослучайное Long для заданной позиции * @@ -105,7 +117,21 @@ interface IChunkSetter { /** * Устанавливает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка */ - operator fun set(x: Int, y: Int, tile: ChunkTile?) + operator fun set(x: Int, y: Int, tile: TileDefinition?): ChunkTile? + /** + * Устанавливает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка + */ + operator fun set(pos: Vector2i, tile: TileDefinition?) = set(pos.x, pos.y, tile) + + /** + * Устанавливает фоновый тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка + */ + fun setBackground(x: Int, y: Int, tile: TileDefinition?): ChunkTile? + + /** + * Устанавливает фоновый тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка + */ + fun setBackground(pos: Vector2i, tile: TileDefinition?) = setBackground(pos.x, pos.y, tile) } interface IMutableChunk : IChunk, IChunkSetter @@ -121,11 +147,16 @@ data class ChunkPos(val x: Int, val y: Int) { val lastBlock get() = Vector2i(((x + 1) shl CHUNK_SHIFT) - 1, ((y + 1) shl CHUNK_SHIFT) - 1) } -class Chunk(val world: World, override val pos: ChunkPos) : IMutableChunk { +open class Chunk(val world: World, override val pos: ChunkPos) : IMutableChunk { /** * Хранит тайлы как x + y * CHUNK_SIZE */ - val tiles = arrayOfNulls(CHUNK_SIZE * CHUNK_SIZE) + private val tiles = arrayOfNulls(CHUNK_SIZE * CHUNK_SIZE) + + /** + * Хранит фоновые тайлы как x + y * CHUNK_SIZE + */ + private val backgroundTiles = arrayOfNulls(CHUNK_SIZE * CHUNK_SIZE) override operator fun get(x: Int, y: Int): ChunkTile? { if (isOutside(x, y)) @@ -134,13 +165,45 @@ class Chunk(val world: World, override val pos: ChunkPos) : IMutableChunk { return tiles[x or (y shl CHUNK_SHIFT)] } - override operator fun set(x: Int, y: Int, tile: ChunkTile?) { + protected operator fun set(x: Int, y: Int, tile: ChunkTile?) { if (isOutside(x, y)) throw IndexOutOfBoundsException("Trying to set tile ${tile?.def?.materialName} at $x $y, but that is outside of chunk's range") tiles[x or (y shl CHUNK_SHIFT)] = tile } + override operator fun set(x: Int, y: Int, tile: TileDefinition?): ChunkTile? { + if (isOutside(x, y)) + throw IndexOutOfBoundsException("Trying to set tile ${tile?.materialName} at $x $y, but that is outside of chunk's range") + + val chunkTile = if (tile != null) ChunkTile(tile) else null + this[x, y] = chunkTile + return chunkTile + } + + override fun getBackground(x: Int, y: Int): ChunkTile? { + if (isOutside(x, y)) + return null + + return backgroundTiles[x or (y shl CHUNK_SHIFT)] + } + + protected fun setBackground(x: Int, y: Int, tile: ChunkTile?) { + if (isOutside(x, y)) + throw IndexOutOfBoundsException("Trying to set background tile ${tile?.def?.materialName} at $x $y, but that is outside of chunk's range") + + backgroundTiles[x or (y shl CHUNK_SHIFT)] = tile + } + + override fun setBackground(x: Int, y: Int, tile: TileDefinition?): ChunkTile? { + if (isOutside(x, y)) + throw IndexOutOfBoundsException("Trying to set background tile ${tile?.materialName} at $x $y, but that is outside of chunk's range") + + val chunkTile = if (tile != null) ChunkTile(tile) else null + setBackground(x, y, chunkTile) + return chunkTile + } + override fun randomLongFor(x: Int, y: Int): Long { return super.randomLongFor(x, y) xor world.seed } @@ -149,13 +212,10 @@ class Chunk(val world: World, override val pos: ChunkPos) : IMutableChunk { val EMPTY = object : IMutableChunk { override val pos = ChunkPos(0, 0) - override fun get(x: Int, y: Int): ChunkTile? { - return null - } - - override fun set(x: Int, y: Int, tile: ChunkTile?) { - - } + override fun get(x: Int, y: Int): ChunkTile? = null + override fun set(x: Int, y: Int, tile: TileDefinition?): ChunkTile? = null + override fun getBackground(x: Int, y: Int): ChunkTile? = null + override fun setBackground(x: Int, y: Int, tile: TileDefinition?): ChunkTile? = null } } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt index e8bfe3dd..2a2cfb78 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt @@ -1,13 +1,20 @@ package ru.dbotthepony.kstarbound.world +import ru.dbotthepony.kstarbound.defs.TileDefinition import ru.dbotthepony.kstarbound.math.Vector2i class World(val seed: Long = 0L) { - val chunkMap = ArrayList>() + private val chunkMap = ArrayList>() + private var lastAccessedChunk: Chunk? = null fun getChunk(pos: ChunkPos): Chunk? { + if (lastAccessedChunk?.pos == pos) { + return lastAccessedChunk + } + for ((k, v) in chunkMap) { if (k == pos) { + lastAccessedChunk = v return v } } @@ -15,9 +22,11 @@ class World(val seed: Long = 0L) { return null } - fun getChunk(pos: Vector2i) = getChunk(ChunkPos(pos)) - fun getOrMakeChunk(pos: ChunkPos): Chunk { + if (lastAccessedChunk?.pos == pos) { + return lastAccessedChunk!! + } + for ((k, v) in chunkMap) { if (k == pos) { return v @@ -25,17 +34,19 @@ class World(val seed: Long = 0L) { } val chunk = Chunk(this, pos) + lastAccessedChunk = chunk chunkMap.add(pos to chunk) return chunk } + fun getChunk(pos: Vector2i) = getChunk(ChunkPos(pos)) fun getOrMakeChunk(pos: Vector2i) = getOrMakeChunk(ChunkPos(pos)) fun getTile(pos: Vector2i): ChunkTile? { return getChunk(pos)?.get(pos.x, pos.y) } - fun setTile(pos: Vector2i, tile: ChunkTile?): Chunk { + fun setTile(pos: Vector2i, tile: TileDefinition?): Chunk { val chunk = getOrMakeChunk(pos) chunk[pos.x and CHUNK_SIZE_FF, pos.y and CHUNK_SIZE_FF] = tile return chunk