Cleaner version of previous commit

This commit is contained in:
DBotThePony 2023-09-04 08:35:31 +07:00
parent 3647643351
commit 3398ba62ee
Signed by: DBot
GPG Key ID: DCC23B5715498507
10 changed files with 148 additions and 230 deletions

View File

@ -18,7 +18,7 @@ import ru.dbotthepony.kstarbound.world.*
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZE
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZEd
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZEf
import ru.dbotthepony.kstarbound.world.api.ITileChunk
import ru.dbotthepony.kstarbound.world.api.ITileAccess
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kvector.arrays.Matrix4fStack
import ru.dbotthepony.kvector.arrays.Matrix4f
@ -41,7 +41,7 @@ const val Z_LEVEL_LIQUID = 10000
class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, ClientChunk>(world, pos), Closeable {
val state: GLStateTracker get() = world.client.gl
private inner class TileLayerRenderer(private val view: ITileChunk, private val isBackground: Boolean) : AutoCloseable {
private inner class TileLayerRenderer(private val view: ITileAccess, private val isBackground: Boolean) : AutoCloseable {
private val layers = TileLayerList()
val bakedMeshes = LinkedList<Pair<ConfiguredStaticMesh, Int>>()
var isDirty = true
@ -153,8 +153,8 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
val debugCollisions get() = world.client.settings.debugCollisions
val posVector2d = Vector2d(x = pos.x * CHUNK_SIZEd, y = pos.y * CHUNK_SIZEd)
private val foregroundRenderer = TileLayerRenderer(localizedForegroundView, isBackground = false)
private val backgroundRenderer = TileLayerRenderer(localizedBackgroundView, isBackground = true)
private val foregroundRenderer = TileLayerRenderer(worldForegroundView, isBackground = false)
private val backgroundRenderer = TileLayerRenderer(worldBackgroundView, isBackground = true)
override fun foregroundChanges() {
super.foregroundChanges()
@ -221,20 +221,20 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
for (x in this.x * SHADOW_GEOMETRY_SQUARE_SIZE until (this.x + 1) * SHADOW_GEOMETRY_SQUARE_SIZE) {
for (y in this.y * SHADOW_GEOMETRY_SQUARE_SIZE until (this.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE) {
if (foregroundView.getTile(x, y).material?.renderParameters?.lightTransparent == false) {
if (x == 0 || foregroundView.getTile(x - 1, y).material?.renderParameters?.lightTransparent != true) {
if (localForegroundView.getTile(x, y).material?.renderParameters?.lightTransparent == false) {
if (x == 0 || localForegroundView.getTile(x - 1, y).material?.renderParameters?.lightTransparent != true) {
line(builder, x.toFloat(), y + 1f, x.toFloat(), y.toFloat())
}
if (x == CHUNK_SIZE - 1 || foregroundView.getTile(x + 1, y).material?.renderParameters?.lightTransparent != true) {
if (x == CHUNK_SIZE - 1 || localForegroundView.getTile(x + 1, y).material?.renderParameters?.lightTransparent != true) {
line(builder, x + 1f, y.toFloat(), x + 1f, y + 1f)
}
if (y == 0 || foregroundView.getTile(x, y - 1).material?.renderParameters?.lightTransparent != true) {
if (y == 0 || localForegroundView.getTile(x, y - 1).material?.renderParameters?.lightTransparent != true) {
line(builder, x.toFloat(), y.toFloat(), x + 1f, y.toFloat())
}
if (y == CHUNK_SIZE - 1 || foregroundView.getTile(x, y + 1).material?.renderParameters?.lightTransparent != true) {
if (y == CHUNK_SIZE - 1 || localForegroundView.getTile(x, y + 1).material?.renderParameters?.lightTransparent != true) {
line(builder, x + 1f, y + 1f, x.toFloat(), y + 1f)
}
}

View File

@ -12,7 +12,6 @@ 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.api.ITileAccess
import ru.dbotthepony.kstarbound.world.api.ITileChunk
import ru.dbotthepony.kstarbound.world.api.ITileState
import ru.dbotthepony.kstarbound.world.api.TileColor
import ru.dbotthepony.kvector.vector.RGBAColor
@ -202,7 +201,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
val bakedBackgroundProgramState = renderers.background(texture)
// private var notifiedDepth = false
private fun tesselateAt(self: ITileState, piece: RenderPiece, getter: ITileChunk, builder: VertexBuilder, pos: Vector2i, offset: Vector2i = Vector2i.ZERO, isModifier: Boolean) {
private fun tesselateAt(self: ITileState, piece: RenderPiece, getter: ITileAccess, builder: VertexBuilder, pos: Vector2i, offset: Vector2i = Vector2i.ZERO, isModifier: Boolean) {
val fx = pos.x.toFloat()
val fy = pos.y.toFloat()
@ -246,7 +245,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
private fun tesselatePiece(
self: ITileState,
matchPiece: RenderMatch,
getter: ITileChunk,
getter: ITileAccess,
layers: TileLayerList,
pos: Vector2i,
thisBuilder: VertexBuilder,
@ -295,7 +294,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
*
* Тесселирует тайлы в нужный VertexBuilder с масштабом согласно константе [PIXELS_IN_STARBOUND_UNITf]
*/
fun tesselate(self: ITileState, getter: ITileChunk, layers: TileLayerList, pos: Vector2i, background: Boolean = false, isModifier: Boolean = false) {
fun tesselate(self: ITileState, getter: ITileAccess, layers: TileLayerList, pos: Vector2i, background: Boolean = false, isModifier: Boolean = false) {
// если у нас нет renderTemplate
// то мы просто не можем его отрисовать
val template = def.renderTemplate.value ?: return

View File

@ -1,71 +0,0 @@
package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kstarbound.world.api.BackgroundChunkView
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZE
import ru.dbotthepony.kstarbound.world.api.ForegroundChunkView
import ru.dbotthepony.kstarbound.world.api.IChunk
import ru.dbotthepony.kstarbound.world.api.IChunkCell
import ru.dbotthepony.kvector.arrays.Object2DArray
/**
* Предоставляет доступ к чанку и его соседям
*
* В основном для использования в местах, где нужен не мир, а определённый чанк мира,
* и при этом координаты проверяются относительно чанка и могут спокойно выйти за его пределы,
* с желанием получить тайл из соседнего чанка
*/
class CellView(
override val pos: ChunkPos,
val left: IChunk?,
val center: IChunk?,
val right: IChunk?,
val topRight: IChunk?,
val top: IChunk?,
val topLeft: IChunk?,
val bottomLeft: IChunk?,
val bottom: IChunk?,
val bottomRight: IChunk?,
) : IChunk {
val backgroundView = BackgroundChunkView(this)
val foregroundView = ForegroundChunkView(this)
override fun getCell(x: Int, y: Int): IChunkCell {
val ix = x + CHUNK_SIZE
val iy = y + CHUNK_SIZE
if (ix in 0 until CHUNK_SIZE * 3 - 1 && iy in 0 until CHUNK_SIZE * 3 - 1) {
return indices[ix, iy].invoke(this) ?: IChunkCell.Companion
} else {
return IChunkCell.Companion
}
}
companion object {
private val indices = Object2DArray.nulls<(CellView) -> IChunkCell?>(CHUNK_SIZE * 3, CHUNK_SIZE * 3) as Object2DArray<(CellView) -> IChunkCell?>
private fun put(half: (CellView) -> IChunk?, x: Int, y: Int) {
for (ix in 0 until CHUNK_SIZE) {
for (iy in 0 until CHUNK_SIZE) {
indices[x + ix, y + iy] = { half(it)?.getCell(ix, iy) }
}
}
}
init {
put(CellView::bottomLeft, 0, 0)
put(CellView::bottom, CHUNK_SIZE, 0)
put(CellView::bottomRight, CHUNK_SIZE * 2, 0)
put(CellView::left, 0, CHUNK_SIZE)
put(CellView::center, CHUNK_SIZE, CHUNK_SIZE)
put(CellView::right, CHUNK_SIZE * 2, CHUNK_SIZE)
put(CellView::topLeft, 0, CHUNK_SIZE * 2)
put(CellView::top, CHUNK_SIZE, CHUNK_SIZE * 2)
put(CellView::topRight, CHUNK_SIZE * 2, CHUNK_SIZE * 2)
}
}
}

View File

@ -7,19 +7,17 @@ import ru.dbotthepony.kbox2d.dynamics.B2Fixture
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import ru.dbotthepony.kstarbound.world.api.BackgroundChunkView
import ru.dbotthepony.kstarbound.world.api.BackgroundLocalizedView
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZE_BITS
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZE
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZE_FF
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZEd
import ru.dbotthepony.kstarbound.world.api.ForegroundChunkView
import ru.dbotthepony.kstarbound.world.api.ForegroundLocalizedView
import ru.dbotthepony.kstarbound.world.api.IChunk
import ru.dbotthepony.kstarbound.world.api.ICellAccess
import ru.dbotthepony.kstarbound.world.api.IChunkCell
import ru.dbotthepony.kstarbound.world.api.ILiquidState
import ru.dbotthepony.kstarbound.world.api.ITileState
import ru.dbotthepony.kstarbound.world.api.OffsetCellAccess
import ru.dbotthepony.kstarbound.world.api.TileColor
import ru.dbotthepony.kstarbound.world.api.TileView
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kstarbound.world.phys.RectTileFlooderDepthFirst
import ru.dbotthepony.kstarbound.world.phys.RectTileFlooderSizeFirst
@ -40,7 +38,7 @@ import kotlin.collections.HashSet
*
* Весь игровой мир будет измеряться в Starbound Unit'ах
*/
abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType, This>>(val world: WorldType, final override val pos: ChunkPos) : IChunk {
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
@ -57,6 +55,35 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
var backgroundChangeset = 0
private set
protected val cells = Object2DArray(CHUNK_SIZE, CHUNK_SIZE, ::Cell)
override fun getCell(x: Int, y: Int): IChunkCell {
return cells[x, y]
}
// 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.chunkMap, pos)
val worldBackgroundView = TileView.background(worldView)
val worldForegroundView = TileView.foreground(worldView)
val aabb = aabbBase + Vector2d(pos.x * CHUNK_SIZE.toDouble(), pos.y * CHUNK_SIZE.toDouble())
var isPhysicsDirty = false
private val collisionCache = ArrayList<AABB>()
private val collisionCacheView = Collections.unmodifiableCollection(collisionCache)
private val body = world.physics.createBody(BodyDef(
position = pos.firstTile.toDoubleVector(),
userData = this
))
private val collisionChains = ArrayList<B2Fixture>()
protected open fun foregroundChanges() {
changeset++
cellChangeset++
@ -86,10 +113,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
world.chunkMap[pos.bottomRight]?.let(block)
}
val aabb = aabbBase + Vector2d(pos.x * CHUNK_SIZE.toDouble(), pos.y * CHUNK_SIZE.toDouble())
var isPhysicsDirty = false
fun markPhysicsDirty() {
if (isPhysicsDirty)
return
@ -98,21 +121,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
world.dirtyPhysicsChunks.add(this as This)
}
protected val cells = Object2DArray(CHUNK_SIZE, CHUNK_SIZE, ::Cell)
val backgroundView = BackgroundChunkView(this)
val foregroundView = ForegroundChunkView(this)
val localizedBackgroundView = BackgroundLocalizedView(pos, world.chunkMap)
val localizedForegroundView = ForegroundLocalizedView(pos, world.chunkMap)
override fun getCell(x: Int, y: Int): IChunkCell {
return cells[x, y]
}
private val collisionCache = ArrayList<AABB>()
private val collisionCacheView = Collections.unmodifiableCollection(collisionCache)
inner class Cell(val x: Int, val y: Int) : IChunkCell {
inner class Tile(private val foreground: Boolean) : ITileState {
private fun change() {
@ -254,13 +262,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
get() = false
}
private val body = world.physics.createBody(BodyDef(
position = pos.firstTile.toDoubleVector(),
userData = this
))
private val collisionChains = ArrayList<B2Fixture>()
fun bakeCollisions() {
if (collisionChangeset == changeset)
return
@ -320,7 +321,7 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
}
override fun randomLongFor(x: Int, y: Int): Long {
return super.randomLongFor(x, y) xor world.seed
return world.chunkMap.randomLongFor(x or pos.x shl CHUNK_SIZE_BITS, y or pos.y shl CHUNK_SIZE_BITS)
}
protected val entities = HashSet<Entity>()

View File

@ -1,13 +1,13 @@
package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZE
import ru.dbotthepony.kstarbound.world.api.IChunk
import ru.dbotthepony.kstarbound.world.api.ICellAccess
import ru.dbotthepony.kstarbound.world.api.IChunkCell
import ru.dbotthepony.kstarbound.world.api.ITileAccess
import ru.dbotthepony.kstarbound.world.api.ITileState
import ru.dbotthepony.kvector.vector.Vector2i
fun IChunk.iterate(fromX: Int = 0, fromY: Int = 0, toX: Int = fromX + CHUNK_SIZE, toY: Int = fromY + CHUNK_SIZE): Iterator<Pair<Vector2i, IChunkCell>> {
fun ICellAccess.iterate(fromX: Int = 0, fromY: Int = 0, toX: Int = fromX + CHUNK_SIZE, toY: Int = fromY + CHUNK_SIZE): Iterator<Pair<Vector2i, IChunkCell>> {
return object : Iterator<Pair<Vector2i, IChunkCell>> {
private var x = fromX
private var y = fromY

View File

@ -14,7 +14,6 @@ import kotlin.math.cos
import kotlin.math.roundToInt
import kotlin.math.sin
const val EARTH_FREEFALL_ACCELERATION = 9.8312 / METRES_IN_STARBOUND_UNIT
data class RayCastResult(

View File

@ -11,13 +11,12 @@ import ru.dbotthepony.kbox2d.dynamics.B2World
import ru.dbotthepony.kbox2d.dynamics.contact.AbstractContact
import ru.dbotthepony.kstarbound.math.*
import ru.dbotthepony.kstarbound.util.Timer
import ru.dbotthepony.kstarbound.world.api.BackgroundAccessView
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZE
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZE_BITS
import ru.dbotthepony.kstarbound.world.api.CHUNK_SIZE_MASK
import ru.dbotthepony.kstarbound.world.api.ForegroundAccessView
import ru.dbotthepony.kstarbound.world.api.ICellAccess
import ru.dbotthepony.kstarbound.world.api.IChunkCell
import ru.dbotthepony.kstarbound.world.api.TileView
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kvector.api.IStruct2d
import ru.dbotthepony.kvector.api.IStruct2i
@ -128,8 +127,12 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
fun inBounds(x: Int, y: Int) = this.x.inBounds(x) && this.y.inBounds(y)
fun inBounds(value: IStruct2i) = this.x.inBounds(value.component1()) && this.y.inBounds(value.component2())
val backgroundView = BackgroundAccessView(this)
val foregroundView = ForegroundAccessView(this)
override fun randomLongFor(x: Int, y: Int): Long {
return super.randomLongFor(x, y) xor seed
}
val background = TileView.background(this)
val foreground = TileView.foreground(this)
abstract operator fun get(x: Int, y: Int): ChunkType?
operator fun get(pos: ChunkPos) = get(pos.x, pos.y)
@ -394,21 +397,6 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
protected abstract fun chunkFactory(pos: ChunkPos): ChunkType
fun getView(pos: ChunkPos): CellView {
return CellView(
pos = pos,
center = chunkMap[pos],
left = chunkMap[pos.left],
top = chunkMap[pos.top],
topLeft = chunkMap[pos.topLeft],
topRight = chunkMap[pos.topRight],
right = chunkMap[pos.right],
bottom = chunkMap[pos.bottom],
bottomLeft = chunkMap[pos.bottomLeft],
bottomRight = chunkMap[pos.bottomRight],
)
}
/**
* Возвращает все чанки, которые пересекаются с заданным [boundingBox]
*/
@ -480,7 +468,6 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
private fun floodLightInto(
lightmap: Int2DArray,
view: CellView,
thisIntensity: Int,
lightBlockerStrength: Int,
posX: Int,
@ -492,7 +479,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
return 1
}
val tile = view.getCell(worldPosX, worldPosY)
val tile = chunkMap.getCell(worldPosX, worldPosY)
val newIntensity: Int
@ -508,7 +495,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
var c = 1
c += floodLightInto(
lightmap, view, newIntensity, lightBlockerStrength,
lightmap, newIntensity, lightBlockerStrength,
posX + 1,
worldPosX + 1,
posY,
@ -516,7 +503,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
)
c += floodLightInto(
lightmap, view, newIntensity, lightBlockerStrength,
lightmap, newIntensity, lightBlockerStrength,
posX - 1,
worldPosX - 1,
posY,
@ -524,7 +511,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
)
c += floodLightInto(
lightmap, view, newIntensity, lightBlockerStrength,
lightmap, newIntensity, lightBlockerStrength,
posX,
worldPosX,
posY + 1,
@ -532,7 +519,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
)
c += floodLightInto(
lightmap, view, newIntensity, lightBlockerStrength,
lightmap, newIntensity, lightBlockerStrength,
posX,
worldPosX,
posY - 1,
@ -564,17 +551,14 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
val lightmap = Int2DArray.allocate(lightIntensity * 2 + 1, lightIntensity * 2 + 1)
val view = getView(ChunkPos.fromPosition(lightPosition))
floodLightInto(
lightmap,
view,
lightIntensity,
lightBlockerStrength,
lightIntensity,
lightPosition.x - view.pos.tileX,
lightPosition.x,
lightIntensity,
lightPosition.y - view.pos.tileY,
lightPosition.y,
)
return lightmap

View File

@ -1,9 +1,51 @@
package ru.dbotthepony.kstarbound.world.api
import ru.dbotthepony.kstarbound.world.ChunkPos
import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.vector.Vector2i
interface ICellAccess {
// relative
fun getCell(x: Int, y: Int): IChunkCell
fun getCell(pos: IStruct2i) = getCell(pos.component1(), pos.component2())
/**
* Возвращает псевдослучайное Long для заданной позиции
*
* Для использования в рендерах и прочих вещах, которым нужно стабильное число на основе своей позиции
*/
fun randomLongFor(x: Int, y: Int): Long {
var long = x * 738548L + y * 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
}
fun randomLongFor(pos: Vector2i) = randomLongFor(pos.x, pos.y)
fun randomDoubleFor(pos: Vector2i) = randomDoubleFor(pos.x, pos.y)
}
class OffsetCellAccess(private val parent: ICellAccess, private val x: Int, private val y: Int) : ICellAccess {
constructor(parent: ICellAccess, offset: IStruct2i) : this(parent, offset.component1(), offset.component2())
constructor(parent: ICellAccess, offset: ChunkPos) : this(parent, offset.firstTile)
override fun getCell(x: Int, y: Int): IChunkCell {
return parent.getCell(x + this.x, y + this.y)
}
override fun randomLongFor(x: Int, y: Int) = parent.randomLongFor(x + this.x, y + this.y)
override fun randomDoubleFor(x: Int, y: Int) = parent.randomDoubleFor(x + this.x, y + this.y)
override fun randomLongFor(pos: Vector2i) = parent.randomLongFor(pos.x + this.x, pos.y + this.y)
override fun randomDoubleFor(pos: Vector2i) = parent.randomDoubleFor(pos.x + this.x, pos.y + this.y)
}

View File

@ -1,46 +0,0 @@
package ru.dbotthepony.kstarbound.world.api
import ru.dbotthepony.kstarbound.world.ChunkPos
import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.vector.Vector2i
interface IChunk : ICellAccess {
val pos: ChunkPos
/**
* Возвращает псевдослучайное Long для заданной позиции
*
* Для использования в рендерах и прочих вещах, которым нужно стабильное число на основе своей позиции
*/
fun randomLongFor(x: Int, y: Int): Long {
var long = (x or (pos.x shl CHUNK_SIZE_BITS)) * 738548L + (y or (pos.y shl CHUNK_SIZE_BITS)) * 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)
}

View File

@ -10,40 +10,50 @@ interface ITileAccess : ICellAccess {
fun getTile(pos: IStruct2i) = getTile(pos.component1(), pos.component2())
}
interface ITileChunk : IChunk, ITileAccess
sealed class TileView(parent: ICellAccess) : ITileAccess, ICellAccess by parent {
private class Foreground(parent: ICellAccess) : TileView(parent) {
override fun getTile(x: Int, y: Int): ITileState {
return getCell(x, y).foreground
}
}
class ForegroundChunkView(private val parent: IChunk) : ITileChunk, IChunk by parent {
override fun getTile(x: Int, y: Int): ITileState {
return parent.getCell(x, y).foreground
}
}
class BackgroundChunkView(private val parent: IChunk) : ITileChunk, IChunk by parent {
override fun getTile(x: Int, y: Int): ITileState {
return parent.getCell(x, y).background
}
}
class ForegroundLocalizedView(override val pos: ChunkPos, private val parent: ICellAccess) : ITileChunk, ICellAccess by parent {
override fun getTile(x: Int, y: Int): ITileState {
return parent.getCell(pos.tileX + x, pos.tileY + y).foreground
}
}
class BackgroundLocalizedView(override val pos: ChunkPos, private val parent: ICellAccess) : ITileChunk, ICellAccess by parent {
override fun getTile(x: Int, y: Int): ITileState {
return parent.getCell(pos.tileX + x, pos.tileY + y).background
}
}
class ForegroundAccessView(private val parent: ICellAccess) : ITileAccess, ICellAccess by parent {
override fun getTile(x: Int, y: Int): ITileState {
return parent.getCell(x, y).foreground
}
}
class BackgroundAccessView(private val parent: ICellAccess) : ITileAccess, ICellAccess by parent {
override fun getTile(x: Int, y: Int): ITileState {
return parent.getCell(x, y).background
private class Background(parent: ICellAccess) : TileView(parent) {
override fun getTile(x: Int, y: Int): ITileState {
return getCell(x, y).background
}
}
companion object {
fun foreground(parent: ICellAccess, xOffset: Int = 0, yOffset: Int = 0): TileView {
if (xOffset == 0 && yOffset == 0) {
return Foreground(parent)
} else {
return Foreground(OffsetCellAccess(parent, xOffset, yOffset))
}
}
fun foreground(parent: ICellAccess, offset: IStruct2i): TileView {
return Foreground(OffsetCellAccess(parent, offset))
}
fun foreground(parent: ICellAccess, offset: ChunkPos): TileView {
return Foreground(OffsetCellAccess(parent, offset))
}
fun background(parent: ICellAccess, xOffset: Int = 0, yOffset: Int = 0): TileView {
if (xOffset == 0 && yOffset == 0) {
return Background(parent)
} else {
return Background(OffsetCellAccess(parent, xOffset, yOffset))
}
}
fun background(parent: ICellAccess, offset: IStruct2i): TileView {
return Background(OffsetCellAccess(parent, offset))
}
fun background(parent: ICellAccess, offset: ChunkPos): TileView {
return Background(OffsetCellAccess(parent, offset))
}
}
}