KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/world/ChunkAPI.kt
2022-09-11 18:50:19 +07:00

195 lines
5.7 KiB
Kotlin

package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import ru.dbotthepony.kvector.vector.nint.Vector2i
const val CHUNK_SHIFT = 5
const val CHUNK_SIZE = 1 shl CHUNK_SHIFT // 32
const val CHUNK_SIZE_FF = CHUNK_SIZE - 1
const val CHUNK_SIZEf = CHUNK_SIZE.toFloat()
const val CHUNK_SIZEd = CHUNK_SIZE.toDouble()
interface ITileState {
val material: TileDefinition?
val modifier: MaterialModifier?
val color: Int
val hueShift: Float
val modifierHueShift: Float
}
interface IMutableTileState : ITileState {
override var material: TileDefinition?
override var modifier: MaterialModifier?
override var color: Int
override var hueShift: Float
override var modifierHueShift: Float
/**
* Выставляет hue shift как байтовое значение в диапазоне 0 .. 255
*/
fun setHueShift(value: Int) {
if (value < 0) {
hueShift = 0f
} else if (value > 255) {
hueShift = 360f
} else {
hueShift = (value / 255f) * 360f
}
}
/**
* Выставляет hue shift как байтовое значение в диапазоне 0 .. 255
*/
fun setModifierHueShift(value: Int) {
if (value < 0) {
modifierHueShift = 0f
} else if (value > 255) {
modifierHueShift = 360f
} else {
modifierHueShift = (value / 255f) * 360f
}
}
}
interface ITileMap {
/**
* Относительная проверка находится ли координата вне границ чанка
*/
fun isOutside(x: Int, y: Int): Boolean {
return x !in 0 until CHUNK_SIZE || y !in 0 until CHUNK_SIZE
}
}
/**
* Предоставляет интерфейс для доступа к тайлам в чанке
*/
interface ITileGetter : ITileMap {
/**
* Возвращает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка
*/
operator fun get(x: Int, y: Int): ITileState
/**
* Возвращает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка
*/
operator fun get(pos: Vector2i) = get(pos.x, pos.y)
/**
* Возвращает итератор пар <Vector2i, Тайл?>
*
* Вектор имеет ОТНОСИТЕЛЬНЫЕ значения внутри самого чанка
*/
val posToTile: Iterator<Pair<Vector2i, ITileState>> get() {
return object : Iterator<Pair<Vector2i, ITileState>> {
private var x = 0
private var y = 0
private fun idx() = x + CHUNK_SIZE * y
override fun hasNext(): Boolean {
return idx() < CHUNK_SIZE * CHUNK_SIZE
}
override fun next(): Pair<Vector2i, ITileState> {
if (!hasNext()) {
throw IllegalStateException("Already iterated everything!")
}
val tile = this@ITileGetter[x, y]
val pos = Vector2i(x, y)
x++
if (x >= CHUNK_SIZE) {
y++
x = 0
}
return pos to tile
}
}
}
}
/**
* Интерфейс предоставляет из себя описание класса, который имеет координаты чанка
*/
interface IChunkPositionable : ITileMap {
val pos: ChunkPos
/**
* Возвращает псевдослучайное Long для заданной позиции
*
* Для использования в рендерах и прочих вещах, которым нужно стабильное число на основе своей позиции
*/
fun randomLongFor(x: Int, y: Int): Long {
var long = (x or (pos.x shl CHUNK_SHIFT)) * 738548L + (y or (pos.y shl CHUNK_SHIFT)) * 2191293543L
long = long xor 8339437585692L
long = (long ushr 4) or (long shl 52)
long *= 7848344324L
long = (long ushr 12) or (long shl 44)
return long
}
/**
* Возвращает псевдослучайное нормализированное Double для заданной позиции
*
* Для использования в рендерах и прочих вещах, которым нужно стабильное число на основе своей позиции
*/
fun randomDoubleFor(x: Int, y: Int): Double {
return (randomLongFor(x, y) / 9.223372036854776E18) / 2.0 + 0.5
}
/**
* Возвращает псевдослучайное Long для заданной позиции
*
* Для использования в рендерах и прочих вещах, которым нужно стабильное число на основе своей позиции
*/
fun randomLongFor(pos: Vector2i) = randomLongFor(pos.x, pos.y)
/**
* Возвращает псевдослучайное нормализированное Double для заданной позиции
*
* Для использования в рендерах и прочих вещах, которым нужно стабильное число на основе своей позиции
*/
fun randomDoubleFor(pos: Vector2i) = randomDoubleFor(pos.x, pos.y)
}
interface ITileChunk : ITileGetter, IChunkPositionable
interface IMutableTileChunk : ITileChunk {
override fun get(x: Int, y: Int): IMutableTileState
override fun get(pos: Vector2i): IMutableTileState {
return get(pos.x, pos.y)
}
}
object EmptyTileState : IMutableTileState {
override var material: TileDefinition?
get() = null
set(value) {}
override var modifier: MaterialModifier?
get() = null
set(value) {}
override var color: Int
get() = 0
set(value) {}
override var hueShift: Float
get() = 0f
set(value) {}
override var modifierHueShift: Float
get() = 0f
set(value) {}
}
object EmptyTileChunk : IMutableTileChunk {
override val pos: ChunkPos
get() = ChunkPos.ZERO
override fun get(x: Int, y: Int): IMutableTileState {
return EmptyTileState
}
}