More streamlining

This commit is contained in:
DBotThePony 2022-09-11 18:50:19 +07:00
parent 96c88aa725
commit ee21636529
Signed by: DBot
GPG Key ID: DCC23B5715498507
13 changed files with 387 additions and 278 deletions

View File

@ -68,11 +68,11 @@ fun main() {
for (y in 0 .. 31) {
for (x in 0 .. 31) {
val materialID = reader.readShort()
val getMat = Starbound.tilesAccessID[materialID.toInt()]
val materialID = reader.readUnsignedShort()
val getMat = Starbound.tilesAccessID[materialID]
if (getMat != null) {
chunk.foreground[x, y] = getMat
chunk.foreground[x, y].material = getMat
hitTile = true
}
@ -84,22 +84,22 @@ fun main() {
val modifier = reader.readUnsignedShort()
val getModifier = Starbound.tileModifiersByIDAccess[modifier]
chunk.foreground[x, y]?.color = colorVariant
chunk.foreground[x, y]?.setHueShift(colorShift)
chunk.foreground[x, y].color = colorVariant
chunk.foreground[x, y].setHueShift(colorShift)
if (getModifier != null && getMat != null) {
chunk.foreground[x, y]?.modifier = getModifier
chunk.foreground[x, y].modifier = getModifier
}
val modifierHueShift = reader.readUnsignedByte()
chunk.foreground[x, y]?.setModifierHueShift(modifierHueShift)
chunk.foreground[x, y].setModifierHueShift(modifierHueShift)
val materialID2 = reader.readShort()
val getMat2 = Starbound.tilesAccessID[materialID2.toInt()]
val materialID2 = reader.readUnsignedShort()
val getMat2 = Starbound.tilesAccessID[materialID2]
if (getMat2 != null) {
chunk.background[x, y] = getMat2
chunk.background[x, y].material = getMat2
hitTile = true
}
@ -113,15 +113,15 @@ fun main() {
val getModifier2 = Starbound.tileModifiersByIDAccess[modifier2]
if (getModifier2 != null && getMat2 != null) {
chunk.background[x, y]?.modifier = getModifier2
chunk.background[x, y].modifier = getModifier2
}
chunk.background[x, y]?.color = colorVariant2
chunk.background[x, y]?.setHueShift(colorShift2)
chunk.background[x, y].color = colorVariant2
chunk.background[x, y].setHueShift(colorShift2)
val modifierHueShift2 = reader.readUnsignedByte()
chunk.background[x, y]?.setModifierHueShift(modifierHueShift2)
chunk.background[x, y].setModifierHueShift(modifierHueShift2)
val liquid = reader.readUnsignedByte()
val liquidLevel = reader.readFloat()

View File

@ -50,28 +50,31 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
layers.clear()
for ((pos, tile) in view.posToTile) {
if (tile != null) {
state.tileRenderers.getTileRenderer(tile.def.materialName).tesselate(tile, view, layers, pos, background = isBackground)
val material = tile.material
val modifier = tile.modifier
if (material != null) {
state.tileRenderers.getTileRenderer(material.materialName).tesselate(tile, view, layers, pos, background = isBackground)
}
if (modifier != null) {
state.tileRenderers.getModifierRenderer(modifier.modName).tesselate(tile, view, layers, pos, background = isBackground, isModifier = true)
}
val modifier = tile.modifier
if (modifier != null) {
state.tileRenderers.getModifierRenderer(modifier.modName).tesselate(tile, view, layers, pos, background = isBackground, isModifier = true)
}
}
}
fun loadRenderers(view: ITileChunk) {
for ((_, tile) in view.posToTile) {
if (tile != null) {
state.tileRenderers.getTileRenderer(tile.def.materialName)
val material = tile.material
val modifier = tile.modifier
val modifier = tile.modifier
if (material != null) {
state.tileRenderers.getTileRenderer(material.materialName)
}
if (modifier != null) {
state.tileRenderers.getModifierRenderer(modifier.modName)
}
if (modifier != null) {
state.tileRenderers.getModifierRenderer(modifier.modName)
}
}
}

View File

@ -10,8 +10,8 @@ import ru.dbotthepony.kstarbound.client.gl.*
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
import ru.dbotthepony.kstarbound.client.gl.vertex.*
import ru.dbotthepony.kstarbound.defs.tile.*
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kstarbound.world.ITileChunk
import ru.dbotthepony.kstarbound.world.ITileState
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.nint.Vector2i
import kotlin.collections.HashMap
@ -171,14 +171,14 @@ private enum class TileRenderTesselateResult {
private fun vertexTextureBuilder() = HeapVertexBuilder(GLAttributeList.TILE, VertexType.QUADS)
private class TileEqualityTester(val definition: TileDefinition) : EqualityRuleTester {
override fun test(thisTile: TileState?, otherTile: TileState?): Boolean {
return otherTile?.def == definition && thisTile?.hueShift == otherTile.hueShift
override fun test(thisTile: ITileState, otherTile: ITileState): Boolean {
return otherTile.material == definition && thisTile.hueShift == otherTile.hueShift
}
}
private class ModifierEqualityTester(val definition: MaterialModifier) : EqualityRuleTester {
override fun test(thisTile: TileState?, otherTile: TileState?): Boolean {
return otherTile?.modifier == definition
override fun test(thisTile: ITileState, otherTile: ITileState): Boolean {
return otherTile.modifier == definition
}
}
@ -196,7 +196,7 @@ class TileRenderer(val state: GLStateTracker, val def: IRenderableTile) {
val bakedBackgroundProgramState = state.tileRenderers.background(texture)
// private var notifiedDepth = false
private fun tesselateAt(self: TileState, piece: RenderPiece, getter: ITileChunk, builder: AbstractVertexBuilder<*>, pos: Vector2i, offset: Vector2i = Vector2i.ZERO, isModifier: Boolean) {
private fun tesselateAt(self: ITileState, piece: RenderPiece, getter: ITileChunk, builder: AbstractVertexBuilder<*>, pos: Vector2i, offset: Vector2i = Vector2i.ZERO, isModifier: Boolean) {
val fx = pos.x.toFloat()
val fy = pos.y.toFloat()
@ -238,7 +238,7 @@ class TileRenderer(val state: GLStateTracker, val def: IRenderableTile) {
}
private fun tesselatePiece(
self: TileState,
self: ITileState,
matchPiece: RenderMatch,
getter: ITileChunk,
layers: TileLayerList,
@ -289,7 +289,7 @@ class TileRenderer(val state: GLStateTracker, val def: IRenderableTile) {
*
* Тесселирует тайлы в нужный VertexBuilder с масштабом согласно константе [PIXELS_IN_STARBOUND_UNITf]
*/
fun tesselate(self: TileState, getter: ITileChunk, layers: TileLayerList, pos: Vector2i, background: Boolean = false, isModifier: Boolean = false) {
fun tesselate(self: ITileState, getter: ITileChunk, layers: TileLayerList, pos: Vector2i, background: Boolean = false, isModifier: Boolean = false) {
// если у нас нет renderTemplate
// то мы просто не можем его отрисовать
val template = def.renderTemplate

View File

@ -12,8 +12,8 @@ import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.io.EnumAdapter
import ru.dbotthepony.kstarbound.io.KConcreteTypeAdapter
import ru.dbotthepony.kstarbound.util.WriteOnce
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kstarbound.world.ITileGetter
import ru.dbotthepony.kstarbound.world.ITileState
import ru.dbotthepony.kvector.vector.nint.Vector2i
import java.util.concurrent.ConcurrentHashMap
@ -38,7 +38,7 @@ data class RenderPiece(
}
fun interface EqualityRuleTester {
fun test(thisTile: TileState?, otherTile: TileState?): Boolean
fun test(thisTile: ITileState, otherTile: ITileState): Boolean
}
data class RenderRuleList(
@ -57,7 +57,7 @@ data class RenderRuleList(
private fun doTest(getter: ITileGetter, equalityTester: EqualityRuleTester, thisPos: Vector2i, offsetPos: Vector2i): Boolean {
return when (type) {
"EqualsSelf" -> equalityTester.test(getter[thisPos], getter[thisPos + offsetPos])
"Connects" -> getter[thisPos + offsetPos] != null
"Connects" -> getter[thisPos + offsetPos].material != null
else -> {
if (LOGGED.add(type)) {

View File

@ -0,0 +1,67 @@
package ru.dbotthepony.kstarbound.util
import java.util.stream.Stream
import java.util.stream.StreamSupport
import kotlin.reflect.KClass
class NotNullTwoDimensionalArray<T : Any>(clazz: KClass<T>, private val width: Int, private val height: Int, initializer: (Int, Int) -> T) {
data class Entry<out T>(
val x: Int,
val y: Int,
val value: T,
)
private val memory: Array<T> = java.lang.reflect.Array.newInstance(clazz.java, width * height) as Array<T>
init {
for (x in 0 until width) {
for (y in 0 until height) {
memory[x + y * width] = initializer.invoke(x, y)
}
}
}
fun isOutside(x: Int, y: Int): Boolean {
return (x !in 0 until width) || (y !in 0 until height)
}
operator fun get(x: Int, y: Int): T {
if (x !in 0 until width) {
throw IndexOutOfBoundsException("X $x is out of bounds between 0 and $width")
}
if (y !in 0 until height) {
throw IndexOutOfBoundsException("Y $y is out of bounds between 0 and $height")
}
return memory[x + y * width]
}
operator fun set(x: Int, y: Int, value: T): T {
if (x !in 0 until width) {
throw IndexOutOfBoundsException("X $x is out of bounds between 0 and $width")
}
if (y !in 0 until height) {
throw IndexOutOfBoundsException("Y $y is out of bounds between 0 and $height")
}
val old = memory[x + y * width]
memory[x + y * width] = value
return old
}
fun stream(): Stream<out T> {
return StreamSupport.stream(ArraySpliterator(memory), false)
}
fun indexedStream(): Stream<out Entry<T>> {
return StreamSupport.stream(IndexedArraySpliterator(memory), false).map {
val x = it.index % width
val y = (it.index - x) / width
Entry(x, y, it.value)
}
}
}
inline fun <reified T : Any> NotNullTwoDimensionalArray(width: Int, height: Int, noinline initializer: (Int, Int) -> T) = NotNullTwoDimensionalArray(T::class, width, height, initializer)

View File

@ -13,6 +13,10 @@ class TwoDimensionalArray<T : Any>(clazz: KClass<T>, private val width: Int, pri
private val memory: Array<T?> = java.lang.reflect.Array.newInstance(clazz.java, width * height) as Array<T?>
fun isOutside(x: Int, y: Int): Boolean {
return (x !in 0 until width) || (y !in 0 until height)
}
operator fun get(x: Int, y: Int): T? {
if (x !in 0 until width) {
throw IndexOutOfBoundsException("X $x is out of bounds between 0 and $width")

View File

@ -8,126 +8,18 @@ import ru.dbotthepony.kstarbound.defs.liquid.LiquidDefinition
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
import ru.dbotthepony.kstarbound.defs.tile.TILE_COLOR_VARIANTS
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import ru.dbotthepony.kstarbound.util.NotNullTwoDimensionalArray
import ru.dbotthepony.kstarbound.util.TwoDimensionalArray
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kstarbound.world.phys.RectTileFlooderDepthFirst
import ru.dbotthepony.kstarbound.world.phys.RectTileFlooderSizeFirst
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.nint.Vector2i
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
/**
* Представляет из себя класс, который содержит состояние тайла на заданной позиции
*/
class TileState(val chunk: Chunk<*, *>.TileLayer, val def: TileDefinition) {
var color = 0
set(value) {
if (value != field) {
if (!def.renderParameters.multiColored) {
throw IllegalStateException("${def.materialName} can't be colored")
}
if (value !in 0 until TILE_COLOR_VARIANTS) {
throw IndexOutOfBoundsException("Tile variant $value is out of possible range 0 to $TILE_COLOR_VARIANTS")
}
field = value
chunk.incChangeset()
}
}
/**
* Выставляет 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
}
}
var hueShift = 0f
set(value) {
var newValue = value % 360f
if (newValue < 0f) {
newValue += 360f
}
if (newValue != field) {
field = newValue
chunk.incChangeset()
}
}
var modifierHueShift = 0f
set(value) {
var newValue = value % 360f
if (newValue < 0f) {
newValue += 360f
}
if (newValue != field) {
field = newValue
chunk.incChangeset()
}
}
var modifier: MaterialModifier? = null
set(value) {
if (value != field) {
field = value
chunk.incChangeset()
}
}
override fun equals(other: Any?): Boolean {
return other is TileState &&
other.color == color &&
other.modifier === modifier &&
other.modifierHueShift == modifierHueShift &&
other.hueShift == hueShift &&
other.def === def
}
override fun toString(): String {
return "ChunkTile[$chunk, material = ${def.materialName}, color = $color, modifier = ${modifier?.modName}]"
}
override fun hashCode(): Int {
var result = chunk.hashCode()
result = 31 * result + def.hashCode()
result = 31 * result + color
result = 31 * result + (modifier?.hashCode() ?: 0)
return result
}
}
data class LiquidState(val chunk: Chunk<*, *>, val def: LiquidDefinition) {
var pressure: Float = 0f
var level: Float = 1f
var isInfinite: Boolean = false
}
private fun ccwSortScore(point: Vector2d, axis: Vector2d): Double {
if (point.x > 0.0) {
return point.dot(axis)
@ -148,14 +40,22 @@ private fun ccwSortScore(point: Vector2d, axis: Vector2d): Double {
*/
abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType, This>>(val world: WorldType, val pos: ChunkPos) {
/**
* Возвращает счётчик изменений чанка
* Возвращает общий счётчик изменений чанка
*/
var changeset = 0
private set
fun incChangeset() {
changeset++
}
/**
* Возвращает счётчик изменений чанка по тайлам
*/
var tileChangeset = 0
private set
/**
* Возвращает счётчик изменений чанка по жидкостям
*/
var liquidChangeset = 0
private set
val left get() = pos.left
val right get() = pos.right
@ -182,18 +82,153 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
foreground.bakeCollisions()
}
inner class LiquidState(val def: LiquidDefinition) {
var pressure: Float = 0f
set(value) {
if (value != field) {
field = value
liquidChangeset++
changeset++
}
}
var level: Float = 1f
set(value) {
if (value != field) {
field = value
liquidChangeset++
changeset++
}
}
var isInfinite: Boolean = false
set(value) {
if (value != field) {
field = value
liquidChangeset++
changeset++
}
}
}
inner class TileLayer : IMutableTileChunk {
inner class TileState(def: TileDefinition? = null) : IMutableTileState {
override var material: TileDefinition? = def
set(value) {
if (value !== field) {
field = value
color = 0
hueShift = 0f
collisionChangeset++
this@TileLayer.changeset++
this@Chunk.changeset++
this@Chunk.tileChangeset++
markPhysicsDirty()
}
}
override var color = 0
set(value) {
val material = material
if (material == null) {
field = 0
return
}
if (value != field) {
if (!material.renderParameters.multiColored) {
throw IllegalStateException("${material.materialName} can't be colored")
}
if (value !in 0 until TILE_COLOR_VARIANTS) {
throw IndexOutOfBoundsException("Tile variant $value is out of possible range 0 to $TILE_COLOR_VARIANTS")
}
field = value
this@TileLayer.changeset++
this@Chunk.changeset++
this@Chunk.tileChangeset++
}
}
override var hueShift = 0f
set(value) {
var newValue = value % 360f
if (newValue < 0f) {
newValue += 360f
}
if (newValue != field) {
field = newValue
this@TileLayer.changeset++
this@Chunk.changeset++
this@Chunk.tileChangeset++
}
}
override var modifierHueShift = 0f
set(value) {
var newValue = value % 360f
if (newValue < 0f) {
newValue += 360f
}
if (newValue != field) {
field = newValue
this@TileLayer.changeset++
this@Chunk.changeset++
this@Chunk.tileChangeset++
}
}
override var modifier: MaterialModifier? = null
set(value) {
if (value != field) {
field = value
modifierHueShift = 0f
this@TileLayer.changeset++
this@Chunk.changeset++
this@Chunk.tileChangeset++
}
}
override fun equals(other: Any?): Boolean {
return other is Chunk<*, *>.TileLayer.TileState &&
other.color == color &&
other.modifier === modifier &&
other.modifierHueShift == modifierHueShift &&
other.hueShift == hueShift &&
other.material === material
}
override fun toString(): String {
return "TileState[${this@TileLayer}, material = ${material?.materialName}, color = $color, modifier = ${modifier?.modName}]"
}
override fun hashCode(): Int {
var result = this@TileLayer.hashCode()
result = 31 * result + material.hashCode()
result = 31 * result + color
result = 31 * result + (modifier?.hashCode() ?: 0)
return result
}
}
/**
* Возвращает счётчик изменений этого слоя
*/
var changeset = 0
private set
fun incChangeset() {
changeset++
this@Chunk.changeset++
}
private val collisionCache = ArrayList<AABB>()
private val collisionCacheView = Collections.unmodifiableCollection(collisionCache)
private var collisionChangeset = -1
@ -223,7 +258,7 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
for (y in 0 .. CHUNK_SIZE_FF) {
for (x in 0..CHUNK_SIZE_FF) {
if (!seen[x or (y shl CHUNK_SHIFT)] && tiles[x or (y shl CHUNK_SHIFT)] != null) {
if (!seen[x or (y shl CHUNK_SHIFT)] && tiles[x, y].material != null) {
val depthFirst = RectTileFlooderDepthFirst(tiles, seen, x, y)
val sizeFirst = RectTileFlooderSizeFirst(tiles, seen, x, y)
val xSpanDepth = depthFirst.maxs.x - depthFirst.mins.x
@ -375,33 +410,10 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
/**
* Хранит тайлы как x + y * CHUNK_SIZE
*/
private val tiles = arrayOfNulls<TileState>(CHUNK_SIZE * CHUNK_SIZE)
private val tiles: NotNullTwoDimensionalArray<TileState> = NotNullTwoDimensionalArray(CHUNK_SIZE, CHUNK_SIZE) { _, _ -> TileState() }
override operator fun get(x: Int, y: Int): TileState? {
if (isOutside(x, y))
return null
return tiles[x or (y shl CHUNK_SHIFT)]
}
operator fun set(x: Int, y: Int, tile: TileState?) {
if (isOutside(x, y))
throw IndexOutOfBoundsException("Trying to set tile ${tile?.def?.materialName} at $x $y, but that is outside of chunk's range")
changeset++
tiles[x or (y shl CHUNK_SHIFT)] = tile
markPhysicsDirty()
}
override operator fun set(x: Int, y: Int, tile: TileDefinition?): TileState? {
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) TileState(this, tile) else null
this[x, y] = chunkTile
changeset++
markPhysicsDirty()
return chunkTile
override operator fun get(x: Int, y: Int): TileState {
return tiles[x, y]
}
override fun randomLongFor(x: Int, y: Int): Long {
@ -418,11 +430,20 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
fun setLiquid(x: Int, y: Int, value: LiquidDefinition?): LiquidState? {
if (value == null) {
return liquidStates.set(x, y, null)
val old = liquidStates.set(x, y, null)
if (old != null) {
changeset++
liquidChangeset++
}
return old
}
val state = LiquidState(this, value)
val state = LiquidState(value)
liquidStates[x, y] = state
changeset++
liquidChangeset++
return state
}
@ -475,13 +496,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
}
companion object {
val EMPTY = object : IMutableTileChunk {
override val pos = ChunkPos(0, 0)
override fun get(x: Int, y: Int): TileState? = null
override fun set(x: Int, y: Int, tile: TileDefinition?): TileState? = null
}
private val aabbBase = AABB(
Vector2d.ZERO,
Vector2d(CHUNK_SIZE.toDouble(), CHUNK_SIZE.toDouble()),

View File

@ -1,5 +1,6 @@
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
@ -10,6 +11,48 @@ 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 {
/**
* Относительная проверка находится ли координата вне границ чанка
@ -26,7 +69,7 @@ interface ITileGetter : ITileMap {
/**
* Возвращает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка
*/
operator fun get(x: Int, y: Int): TileState?
operator fun get(x: Int, y: Int): ITileState
/**
* Возвращает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка
@ -38,8 +81,8 @@ interface ITileGetter : ITileMap {
*
* Вектор имеет ОТНОСИТЕЛЬНЫЕ значения внутри самого чанка
*/
val posToTile: Iterator<Pair<Vector2i, TileState?>> get() {
return object : Iterator<Pair<Vector2i, TileState?>> {
val posToTile: Iterator<Pair<Vector2i, ITileState>> get() {
return object : Iterator<Pair<Vector2i, ITileState>> {
private var x = 0
private var y = 0
@ -49,7 +92,7 @@ interface ITileGetter : ITileMap {
return idx() < CHUNK_SIZE * CHUNK_SIZE
}
override fun next(): Pair<Vector2i, TileState?> {
override fun next(): Pair<Vector2i, ITileState> {
if (!hasNext()) {
throw IllegalStateException("Already iterated everything!")
}
@ -114,20 +157,38 @@ interface IChunkPositionable : ITileMap {
fun randomDoubleFor(pos: Vector2i) = randomDoubleFor(pos.x, pos.y)
}
/**
* Предоставляет интерфейс по установке тайлов в чанке
*/
interface ITileSetter : ITileMap {
/**
* Устанавливает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка
*/
operator fun set(x: Int, y: Int, tile: TileDefinition?): TileState?
/**
* Устанавливает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка
*/
operator fun set(pos: Vector2i, tile: TileDefinition?) = set(pos.x, pos.y, tile)
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)
}
}
interface ITileGetterSetter : ITileGetter, ITileSetter
interface ITileChunk : ITileGetter, IChunkPositionable
interface IMutableTileChunk : ITileChunk, ITileSetter
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
}
}

View File

@ -22,38 +22,38 @@ open class TileView(
open val bottomLeft: ITileChunk?,
open val bottomRight: ITileChunk?,
) : ITileChunk {
override fun get(x: Int, y: Int): TileState? {
override fun get(x: Int, y: Int): ITileState {
if (x in 0 ..CHUNK_SIZE_FF) {
if (y in 0 ..CHUNK_SIZE_FF) {
return center[x, y]
}
if (y < 0) {
return bottom?.get(x, y + CHUNK_SIZE)
return bottom?.get(x, y + CHUNK_SIZE) ?: EmptyTileState
} else {
return top?.get(x, y - CHUNK_SIZE)
return top?.get(x, y - CHUNK_SIZE) ?: EmptyTileState
}
}
if (x < 0) {
if (y in 0 ..CHUNK_SIZE_FF) {
return left?.get(x + CHUNK_SIZE, y)
return left?.get(x + CHUNK_SIZE, y) ?: EmptyTileState
}
if (y < 0) {
return bottomLeft?.get(x + CHUNK_SIZE, y + CHUNK_SIZE)
return bottomLeft?.get(x + CHUNK_SIZE, y + CHUNK_SIZE) ?: EmptyTileState
} else {
return topLeft?.get(x + CHUNK_SIZE, y - CHUNK_SIZE)
return topLeft?.get(x + CHUNK_SIZE, y - CHUNK_SIZE) ?: EmptyTileState
}
} else {
if (y in 0 ..CHUNK_SIZE_FF) {
return right?.get(x - CHUNK_SIZE, y)
return right?.get(x - CHUNK_SIZE, y) ?: EmptyTileState
}
if (y < 0) {
return bottomRight?.get(x - CHUNK_SIZE, y + CHUNK_SIZE)
return bottomRight?.get(x - CHUNK_SIZE, y + CHUNK_SIZE) ?: EmptyTileState
} else {
return topRight?.get(x - CHUNK_SIZE, y - CHUNK_SIZE)
return topRight?.get(x - CHUNK_SIZE, y - CHUNK_SIZE) ?: EmptyTileState
}
}
}
@ -75,39 +75,7 @@ class MutableTileView(
override val bottomLeft: IMutableTileChunk?,
override val bottomRight: IMutableTileChunk?,
) : TileView(center, right, top, topRight, topLeft, left, bottom, bottomLeft, bottomRight), IMutableTileChunk {
override fun set(x: Int, y: Int, tile: TileDefinition?): TileState? {
if (x in 0 .. CHUNK_SIZE_FF) {
if (y in 0 .. CHUNK_SIZE_FF) {
return center.set(x, y, tile)
}
if (y < 0) {
return bottom?.set(x, y + CHUNK_SIZE, tile)
} else {
return top?.set(x, y - CHUNK_SIZE, tile)
}
}
if (x < 0) {
if (y in 0 .. CHUNK_SIZE_FF) {
return left?.set(x + CHUNK_SIZE, y, tile)
}
if (y < 0) {
return bottomLeft?.set(x + CHUNK_SIZE, y + CHUNK_SIZE, tile)
} else {
return topLeft?.set(x + CHUNK_SIZE, y - CHUNK_SIZE, tile)
}
} else {
if (y in 0 .. CHUNK_SIZE_FF) {
return right?.set(x - CHUNK_SIZE, y, tile)
}
if (y < 0) {
return bottomRight?.set(x - CHUNK_SIZE, y + CHUNK_SIZE, tile)
} else {
return topRight?.set(x - CHUNK_SIZE, y - CHUNK_SIZE, tile)
}
}
override fun get(x: Int, y: Int): IMutableTileState {
return super<TileView>.get(x, y) as IMutableTileState
}
}

View File

@ -323,26 +323,14 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
)
}
fun getTile(pos: Vector2i): TileState? {
fun getTile(pos: Vector2i): ITileState? {
return get(ChunkPos.fromTilePosition(pos))?.foreground?.get(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
}
fun setTile(pos: Vector2i, tile: TileDefinition?): ChunkType {
val chunk = computeIfAbsent(ChunkPos.fromTilePosition(pos))
chunk.foreground[ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y)] = tile
return chunk
}
fun getBackgroundTile(pos: Vector2i): TileState? {
fun getBackgroundTile(pos: Vector2i): ITileState? {
return get(ChunkPos.fromTilePosition(pos))?.background?.get(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
}
fun setBackgroundTile(pos: Vector2i, tile: TileDefinition?): ChunkType {
val chunk = computeIfAbsent(ChunkPos.fromTilePosition(pos))
chunk.background[ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y)] = tile
return chunk
}
/**
* Возвращает все чанки, которые пересекаются с заданным [boundingBox]
*/

View File

@ -1,12 +1,14 @@
package ru.dbotthepony.kstarbound.world.phys
import ru.dbotthepony.kstarbound.util.NotNullTwoDimensionalArray
import ru.dbotthepony.kstarbound.world.CHUNK_SHIFT
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_FF
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kstarbound.world.Chunk
import ru.dbotthepony.kstarbound.world.ITileState
import ru.dbotthepony.kvector.vector.nint.Vector2i
class RectTileFlooderDepthFirst(
private val tiles: Array<TileState?>,
private val tiles: NotNullTwoDimensionalArray<out ITileState>,
private val seen: BooleanArray,
rootx: Int,
rooty: Int
@ -23,7 +25,7 @@ class RectTileFlooderDepthFirst(
return false
}
return !seen[x or (y shl CHUNK_SHIFT)] && tiles[x or (y shl CHUNK_SHIFT)] != null
return !seen[x or (y shl CHUNK_SHIFT)] && tiles[x, y].material != null
}
init {

View File

@ -1,12 +1,13 @@
package ru.dbotthepony.kstarbound.world.phys
import ru.dbotthepony.kstarbound.util.NotNullTwoDimensionalArray
import ru.dbotthepony.kstarbound.world.CHUNK_SHIFT
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_FF
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kstarbound.world.ITileState
import ru.dbotthepony.kvector.vector.nint.Vector2i
class RectTileFlooderSizeFirst(
private val tiles: Array<TileState?>,
private val tiles: NotNullTwoDimensionalArray<out ITileState>,
private val seen: BooleanArray,
private val rootx: Int,
private val rooty: Int
@ -23,7 +24,7 @@ class RectTileFlooderSizeFirst(
return false
}
return !seen[x or (y shl CHUNK_SHIFT)] && tiles[x or (y shl CHUNK_SHIFT)] != null
return !seen[x or (y shl CHUNK_SHIFT)] && tiles[x, y].material != null
}
private var widthPositive = 0

View File

@ -1,8 +1,9 @@
package ru.dbotthepony.kstarbound.world.phys
import ru.dbotthepony.kstarbound.util.NotNullTwoDimensionalArray
import ru.dbotthepony.kstarbound.world.CHUNK_SHIFT
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_FF
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kstarbound.world.ITileState
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
private data class TileExposure(
@ -14,7 +15,7 @@ private data class TileExposure(
)
private class TileFlooder(
private val tiles: Array<TileState?>,
private val tiles: NotNullTwoDimensionalArray<out ITileState>,
private val seen: BooleanArray,
rootx: Int,
rooty: Int
@ -33,7 +34,7 @@ private class TileFlooder(
return false
}
return tiles[x or (y shl CHUNK_SHIFT)] != null
return tiles[x, y].material != null
}
private fun visit(x: Int, y: Int) {
@ -71,4 +72,4 @@ private class TileFlooder(
init {
visit(rootx, rooty)
}
}
}