More streamlining
This commit is contained in:
parent
96c88aa725
commit
ee21636529
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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)
|
@ -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")
|
||||
|
@ -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()),
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
*/
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user