KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/world/Chunk.kt

169 lines
4.6 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kommons.arrays.Object2DArray
import ru.dbotthepony.kommons.util.AABB
import ru.dbotthepony.kommons.vector.Vector2d
import ru.dbotthepony.kstarbound.network.LegacyNetworkCellState
import ru.dbotthepony.kstarbound.world.api.AbstractCell
import ru.dbotthepony.kstarbound.world.api.ICellAccess
import ru.dbotthepony.kstarbound.world.api.ImmutableCell
import ru.dbotthepony.kstarbound.world.api.OffsetCellAccess
import ru.dbotthepony.kstarbound.world.api.TileView
import java.util.concurrent.CopyOnWriteArraySet
/**
* Чанк мира
*
* Хранит в себе тайлы и ентити внутри себя
*
* Считается, что один тайл имеет форму квадрата и сторона квадрата примерно равна полуметру,
* что будет называться Starbound Unit
*
* Весь игровой мир будет измеряться в Starbound Unit'ах
*/
abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType, This>>(
val world: WorldType,
val pos: ChunkPos,
) : ICellAccess {
var changeset = 0
private set
var tileChangeset = 0
private set
var liquidChangeset = 0
private set
var cellChangeset = 0
private set
var foregroundChangeset = 0
private set
var backgroundChangeset = 0
private set
val width = (world.geometry.size.x - pos.tileX).coerceAtMost(CHUNK_SIZE)
val height = (world.geometry.size.y - pos.tileY).coerceAtMost(CHUNK_SIZE)
// local cells' tile access
val localBackgroundView = TileView.Background(this)
val localForegroundView = TileView.Foreground(this)
// relative world cells access (accessing 0, 0 will lookup cell in world, relative to this chunk)
val worldView = OffsetCellAccess(world, pos.x * CHUNK_SIZE, pos.y * CHUNK_SIZE)
val worldBackgroundView = TileView.Background(worldView)
val worldForegroundView = TileView.Foreground(worldView)
val aabb = aabbBase + Vector2d(pos.x * CHUNK_SIZE.toDouble(), pos.y * CHUNK_SIZE.toDouble())
// TODO: maybe fit them into "width" and "height" variables added recently?
protected val cells = lazy {
Object2DArray(CHUNK_SIZE, CHUNK_SIZE, AbstractCell.NULL)
}
protected val tileHealthForeground = lazy {
Object2DArray(CHUNK_SIZE, CHUNK_SIZE) { _, _ -> TileHealth.Tile() }
}
protected val tileHealthBackground = lazy {
Object2DArray(CHUNK_SIZE, CHUNK_SIZE) { _, _ -> TileHealth.Tile() }
}
fun loadCells(source: Object2DArray<out AbstractCell>) {
val ours = cells.value
source.checkSizeEquals(ours)
for (x in 0 until CHUNK_SIZE) {
for (y in 0 until CHUNK_SIZE) {
ours[x, y] = source[x, y].immutable()
}
}
}
override fun getCell(x: Int, y: Int): AbstractCell {
if (!cells.isInitialized())
return AbstractCell.NULL
return cells.value[x, y]
}
override fun getCellDirect(x: Int, y: Int): AbstractCell {
return getCell(x, y)
}
override fun setCell(x: Int, y: Int, cell: AbstractCell): Boolean {
val old = if (cells.isInitialized()) cells.value[x, y] else AbstractCell.NULL
val new = cell.immutable()
if (old != new) {
cells.value[x, y] = new
if (old.foreground != new.foreground) {
foregroundChanges(x, y, new)
}
if (old.background != new.background) {
backgroundChanges(x, y, new)
}
if (old.liquid != new.liquid) {
liquidChanges(x, y, new)
}
cellChanges(x, y, new)
}
return true
}
protected open fun foregroundChanges(x: Int, y: Int, cell: ImmutableCell) {
cellChanges(x, y, cell)
tileChangeset++
foregroundChangeset++
}
protected open fun backgroundChanges(x: Int, y: Int, cell: ImmutableCell) {
cellChanges(x, y, cell)
tileChangeset++
backgroundChangeset++
}
protected open fun liquidChanges(x: Int, y: Int, cell: ImmutableCell) {
cellChanges(x, y, cell)
liquidChangeset++
}
protected open fun cellChanges(x: Int, y: Int, cell: ImmutableCell) {
changeset++
cellChangeset++
}
protected inline fun forEachNeighbour(block: (This) -> Unit) {
world.chunkMap[pos.left]?.let(block)
world.chunkMap[pos.right]?.let(block)
world.chunkMap[pos.top]?.let(block)
world.chunkMap[pos.bottom]?.let(block)
world.chunkMap[pos.topLeft]?.let(block)
world.chunkMap[pos.topRight]?.let(block)
world.chunkMap[pos.bottomLeft]?.let(block)
world.chunkMap[pos.bottomRight]?.let(block)
}
override fun toString(): String {
return "${this::class.simpleName}(pos=$pos, world=$world)"
}
open fun remove() {
}
open fun tick() {
}
companion object {
private val aabbBase = AABB(
Vector2d.ZERO,
Vector2d(CHUNK_SIZE.toDouble(), CHUNK_SIZE.toDouble()),
)
}
}