Fix memory requirements of previous commit :)
This commit is contained in:
parent
e134554879
commit
318b689d2d
@ -16,7 +16,7 @@ import java.io.DataOutputStream
|
|||||||
|
|
||||||
class ChunkCellsPacket(val pos: ChunkPos, val data: List<ImmutableCell>) : IClientPacket {
|
class ChunkCellsPacket(val pos: ChunkPos, val data: List<ImmutableCell>) : IClientPacket {
|
||||||
constructor(stream: DataInputStream, isLegacy: Boolean) : this(stream.readChunkPos(), stream.readCollection { MutableCell().read(stream).immutable() })
|
constructor(stream: DataInputStream, isLegacy: Boolean) : this(stream.readChunkPos(), stream.readCollection { MutableCell().read(stream).immutable() })
|
||||||
constructor(chunk: Chunk<*, *, *>) : this(chunk.pos, ArrayList<ImmutableCell>(CHUNK_SIZE * CHUNK_SIZE).also {
|
constructor(chunk: Chunk<*, *>) : this(chunk.pos, ArrayList<ImmutableCell>(CHUNK_SIZE * CHUNK_SIZE).also {
|
||||||
for (x in 0 until CHUNK_SIZE) {
|
for (x in 0 until CHUNK_SIZE) {
|
||||||
for (y in 0 until CHUNK_SIZE) {
|
for (y in 0 until CHUNK_SIZE) {
|
||||||
it.add(chunk.getCell(x, y).immutable())
|
it.add(chunk.getCell(x, y).immutable())
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.world
|
package ru.dbotthepony.kstarbound.client.world
|
||||||
|
|
||||||
import ru.dbotthepony.kommons.arrays.Object2DArray
|
|
||||||
import ru.dbotthepony.kstarbound.world.Chunk
|
import ru.dbotthepony.kstarbound.world.Chunk
|
||||||
import ru.dbotthepony.kstarbound.world.ChunkPos
|
import ru.dbotthepony.kstarbound.world.ChunkPos
|
||||||
import ru.dbotthepony.kstarbound.world.ChunkState
|
import ru.dbotthepony.kstarbound.world.ChunkState
|
||||||
import ru.dbotthepony.kstarbound.world.api.AbstractCell
|
import ru.dbotthepony.kstarbound.world.api.AbstractCell
|
||||||
import ru.dbotthepony.kstarbound.world.api.ImmutableCell
|
import ru.dbotthepony.kstarbound.world.api.ImmutableCell
|
||||||
|
|
||||||
class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, ClientChunk, ClientChunk.ChunkCell>(world, pos) {
|
class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, ClientChunk>(world, pos) {
|
||||||
inner class ChunkCell(x: Int, y: Int) : Chunk<ClientWorld, ClientChunk, ClientChunk.ChunkCell>.ChunkCell(x, y)
|
|
||||||
|
|
||||||
override val cells: Object2DArray<ChunkCell> = Object2DArray(width, height, ::ChunkCell)
|
|
||||||
|
|
||||||
override val state: ChunkState
|
override val state: ChunkState
|
||||||
get() = ChunkState.FULL
|
get() = ChunkState.FULL
|
||||||
|
|
||||||
|
@ -62,13 +62,7 @@ import kotlin.coroutines.cancellation.CancellationException
|
|||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.resumeWithException
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|
||||||
class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, ServerChunk, ServerChunk.ChunkCell>(world, pos) {
|
class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, ServerChunk>(world, pos) {
|
||||||
inner class ChunkCell(x: Int, y: Int) : Chunk<ServerWorld, ServerChunk, ServerChunk.ChunkCell>.ChunkCell(x, y) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override val cells: Object2DArray<ChunkCell> = Object2DArray(width, height, ::ChunkCell)
|
|
||||||
|
|
||||||
override var state: ChunkState = ChunkState.FRESH
|
override var state: ChunkState = ChunkState.FRESH
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -156,9 +150,11 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
if (world.template.worldLayout == null || world.template.worldParameters is FloatingDungeonWorldParameters) {
|
if (world.template.worldLayout == null || world.template.worldParameters is FloatingDungeonWorldParameters) {
|
||||||
// skip since no cells will be generated anyway
|
// skip since no cells will be generated anyway
|
||||||
|
|
||||||
|
val cells = cells.value
|
||||||
|
|
||||||
for (x in 0 until width) {
|
for (x in 0 until width) {
|
||||||
for (y in 0 until height) {
|
for (y in 0 until height) {
|
||||||
cells[x, y].setStateQuiet(AbstractCell.EMPTY)
|
cells[x, y] = AbstractCell.EMPTY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,6 +187,8 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
if (world.template.worldLayout != null && world.template.worldParameters !is FloatingDungeonWorldParameters) {
|
if (world.template.worldLayout != null && world.template.worldParameters !is FloatingDungeonWorldParameters) {
|
||||||
placeGrass()
|
placeGrass()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signalChunkContentsUpdated()
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunkState.FRESH -> throw RuntimeException()
|
ChunkState.FRESH -> throw RuntimeException()
|
||||||
@ -401,15 +399,10 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
temporary.forEach { if (it.targetState <= state) it.chunk.complete(this) }
|
temporary.forEach { if (it.targetState <= state) it.chunk.complete(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copyCells(): Object2DArray<ImmutableCell> {
|
|
||||||
return Object2DArray(CHUNK_SIZE, CHUNK_SIZE) { x, y -> cells[x, y].state }
|
|
||||||
}
|
|
||||||
|
|
||||||
data class DamageResult(val result: TileDamageResult, val health: TileHealth? = null, val stateBefore: AbstractCell? = null)
|
data class DamageResult(val result: TileDamageResult, val health: TileHealth? = null, val stateBefore: AbstractCell? = null)
|
||||||
|
|
||||||
fun damageTile(pos: Vector2i, isBackground: Boolean, sourcePosition: Vector2d, damage: TileDamage, source: AbstractEntity? = null): DamageResult {
|
fun damageTile(pos: Vector2i, isBackground: Boolean, sourcePosition: Vector2d, damage: TileDamage, source: AbstractEntity? = null): DamageResult {
|
||||||
val cellState = cells[pos.x, pos.y]
|
val cell = cells.value[pos.x, pos.y]
|
||||||
val cell = cellState.state
|
|
||||||
|
|
||||||
if (cell.isIndestructible || cell.tile(isBackground).material.value.isMeta) {
|
if (cell.isIndestructible || cell.tile(isBackground).material.value.isMeta) {
|
||||||
return DamageResult(TileDamageResult.NONE)
|
return DamageResult(TileDamageResult.NONE)
|
||||||
@ -423,7 +416,7 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
result = TileDamageResult.PROTECTED
|
result = TileDamageResult.PROTECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
val health = if (isBackground) cellState.backgroundHealth else cellState.foregroundHealth
|
val health = if (isBackground) backgroundHealth.computeIfAbsent(pos) { TileHealth.Tile() } else foregroundHealth.computeIfAbsent(pos) { TileHealth.Tile() }
|
||||||
val tile = cell.tile(isBackground)
|
val tile = cell.tile(isBackground)
|
||||||
|
|
||||||
val params = if (!damage.type.isPenetrating && tile.modifier.value.breaksWithTile) {
|
val params = if (!damage.type.isPenetrating && tile.modifier.value.breaksWithTile) {
|
||||||
@ -436,8 +429,6 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
onTileHealthUpdate(pos.x, pos.y, isBackground, health)
|
onTileHealthUpdate(pos.x, pos.y, isBackground, health)
|
||||||
|
|
||||||
if (health.isDead) {
|
if (health.isDead) {
|
||||||
damagedCells.remove(pos)
|
|
||||||
|
|
||||||
val drops = ArrayList<ItemDescriptor>()
|
val drops = ArrayList<ItemDescriptor>()
|
||||||
|
|
||||||
val copyHealth = health.copy()
|
val copyHealth = health.copy()
|
||||||
@ -475,32 +466,24 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
setCell(pos.x, pos.y, mCell.immutable())
|
setCell(pos.x, pos.y, mCell.immutable())
|
||||||
health.reset()
|
|
||||||
return DamageResult(result, copyHealth, cell)
|
return DamageResult(result, copyHealth, cell)
|
||||||
} else {
|
} else {
|
||||||
damagedCells.add(pos)
|
|
||||||
return DamageResult(result, health, cell)
|
return DamageResult(result, health, cell)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val damagedCells = ObjectArraySet<Vector2i>()
|
|
||||||
|
|
||||||
fun tileDamagePackets(): List<TileDamageUpdatePacket> {
|
fun tileDamagePackets(): List<TileDamageUpdatePacket> {
|
||||||
val result = ArrayList<TileDamageUpdatePacket>()
|
val result = ArrayList<TileDamageUpdatePacket>()
|
||||||
|
|
||||||
for (x in 0 until width) {
|
for ((pos, health) in backgroundHealth) {
|
||||||
for (y in 0 until height) {
|
if (!health.isHealthy) {
|
||||||
val health = cells[x, y].backgroundHealth
|
result.add(TileDamageUpdatePacket(this.pos.tileX + pos.x, this.pos.tileY + pos.y, true, health))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!health.isHealthy) {
|
for ((pos, health) in foregroundHealth) {
|
||||||
result.add(TileDamageUpdatePacket(pos.tileX + x, pos.tileY + y, true, health))
|
if (!health.isHealthy) {
|
||||||
}
|
result.add(TileDamageUpdatePacket(this.pos.tileX + pos.x, this.pos.tileY + pos.y, false, health))
|
||||||
|
|
||||||
val health2 = cells[x, y].foregroundHealth
|
|
||||||
|
|
||||||
if (!health2.isHealthy) {
|
|
||||||
result.add(TileDamageUpdatePacket(pos.tileX + x, pos.tileY + y, false, health2))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,23 +523,18 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
|
|
||||||
super.tick()
|
super.tick()
|
||||||
|
|
||||||
damagedCells.removeIf { (x, y) ->
|
foregroundHealth.entries.removeIf { (pos, health) ->
|
||||||
val health = cells[x, y].foregroundHealth
|
val (x, y) = pos
|
||||||
val health2 = cells[x, y].backgroundHealth
|
val remove = !health.tick(cells.value[x, y].foreground.material.value.actualDamageTable)
|
||||||
|
onTileHealthUpdate(x, y, false, health)
|
||||||
|
remove
|
||||||
|
}
|
||||||
|
|
||||||
var any = false
|
backgroundHealth.entries.removeIf { (pos, health) ->
|
||||||
|
val (x, y) = pos
|
||||||
if (health.isTicking) {
|
val remove = !health.tick(cells.value[x, y].background.material.value.actualDamageTable)
|
||||||
any = health.tick(cells[x, y].state.foreground.material.value.actualDamageTable) || any
|
onTileHealthUpdate(x, y, true, health)
|
||||||
onTileHealthUpdate(x, y, false, health)
|
remove
|
||||||
}
|
|
||||||
|
|
||||||
if (health2.isTicking) {
|
|
||||||
any = health2.tick(cells[x, y].state.background.material.value.actualDamageTable) || any
|
|
||||||
onTileHealthUpdate(x, y, false, health2)
|
|
||||||
}
|
|
||||||
|
|
||||||
!any
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,15 +569,22 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun legacyNetworkCells(): Object2DArray<LegacyNetworkCellState> {
|
fun legacyNetworkCells(): Object2DArray<LegacyNetworkCellState> {
|
||||||
return Object2DArray(width, height) { a, b -> cells[a, b].state.toLegacyNet() }
|
if (cells.isInitialized()) {
|
||||||
|
val cells = cells.value
|
||||||
|
return Object2DArray(width, height) { a, b -> cells[a, b].toLegacyNet() }
|
||||||
|
} else {
|
||||||
|
return Object2DArray(width, height, AbstractCell.NULL.toLegacyNet())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prepareCells() {
|
private fun prepareCells() {
|
||||||
|
val cells = cells.value
|
||||||
|
|
||||||
for (x in 0 until width) {
|
for (x in 0 until width) {
|
||||||
for (y in 0 until height) {
|
for (y in 0 until height) {
|
||||||
val info = world.template.cellInfo(pos.tileX + x, pos.tileY + y)
|
val info = world.template.cellInfo(pos.tileX + x, pos.tileY + y)
|
||||||
|
|
||||||
val state = cells[x, y].state.mutable()
|
val state = cells[x, y].mutable()
|
||||||
|
|
||||||
state.blockBiome = info.blockBiomeIndex
|
state.blockBiome = info.blockBiomeIndex
|
||||||
state.envBiome = info.environmentBiomeIndex
|
state.envBiome = info.environmentBiomeIndex
|
||||||
@ -643,15 +628,17 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cells[x, y].setStateQuiet(state.immutable())
|
cells[x, y] = state.immutable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun finalizeCells() {
|
private fun finalizeCells() {
|
||||||
|
val cells = cells.value
|
||||||
|
|
||||||
for (x in 0 until width) {
|
for (x in 0 until width) {
|
||||||
for (y in 0 until height) {
|
for (y in 0 until height) {
|
||||||
val cell = cells[x, y].state.mutable()
|
val cell = cells[x, y].mutable()
|
||||||
val info by lazy { world.template.cellInfo(pos.tileX + x, pos.tileY + y) }
|
val info by lazy { world.template.cellInfo(pos.tileX + x, pos.tileY + y) }
|
||||||
|
|
||||||
if (cell.liquid.isInfinite) {
|
if (cell.liquid.isInfinite) {
|
||||||
@ -676,7 +663,7 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
replaceBiomeBlocks(cell, info)
|
replaceBiomeBlocks(cell, info)
|
||||||
cells[x, y].state = cell.immutable()
|
cells[x, y] = cell.immutable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -709,11 +696,13 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun replaceBiomeBlocks() {
|
private fun replaceBiomeBlocks() {
|
||||||
|
val cells = cells.value
|
||||||
|
|
||||||
for (x in 0 until width) {
|
for (x in 0 until width) {
|
||||||
for (y in 0 until height) {
|
for (y in 0 until height) {
|
||||||
val cell = cells[x, y].state.mutable()
|
val cell = cells[x, y].mutable()
|
||||||
replaceBiomeBlocks(cell, world.template.cellInfo(pos.tileX + x, pos.tileY + y))
|
replaceBiomeBlocks(cell, world.template.cellInfo(pos.tileX + x, pos.tileY + y))
|
||||||
cells[x, y].state = cell.immutable()
|
cells[x, y] = cell.immutable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -789,10 +778,12 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun placeGrass() {
|
private fun placeGrass() {
|
||||||
|
val cells = cells.value
|
||||||
|
|
||||||
for (x in 0 until width) {
|
for (x in 0 until width) {
|
||||||
for (y in 0 until height) {
|
for (y in 0 until height) {
|
||||||
val biome = world.template.cellInfo(pos.tileX + x, pos.tileY + y).blockBiome ?: continue
|
val biome = world.template.cellInfo(pos.tileX + x, pos.tileY + y).blockBiome ?: continue
|
||||||
val cell = cells[x, y].state
|
val cell = cells[x, y]
|
||||||
|
|
||||||
// determine layer for grass mod calculation
|
// determine layer for grass mod calculation
|
||||||
val isBackground = cell.foreground.material.isEmptyTile
|
val isBackground = cell.foreground.material.isEmptyTile
|
||||||
@ -853,7 +844,7 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
modify.background.modifierHueShift = biome.hueShift(modify.background.modifier)
|
modify.background.modifierHueShift = biome.hueShift(modify.background.modifier)
|
||||||
modify.foreground.modifierHueShift = biome.hueShift(modify.foreground.modifier)
|
modify.foreground.modifierHueShift = biome.hueShift(modify.foreground.modifier)
|
||||||
|
|
||||||
cells[x, y].state = modify.immutable()
|
cells[x, y] = modify.immutable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ru.dbotthepony.kstarbound.world
|
package ru.dbotthepony.kstarbound.world
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||||
|
import ru.dbotthepony.kommons.arrays.Boolean2DArray
|
||||||
import ru.dbotthepony.kommons.arrays.Object2DArray
|
import ru.dbotthepony.kommons.arrays.Object2DArray
|
||||||
import ru.dbotthepony.kommons.util.AABB
|
import ru.dbotthepony.kommons.util.AABB
|
||||||
import ru.dbotthepony.kommons.util.AABBi
|
import ru.dbotthepony.kommons.util.AABBi
|
||||||
@ -17,6 +18,7 @@ import ru.dbotthepony.kstarbound.world.physics.CollisionPoly
|
|||||||
import ru.dbotthepony.kstarbound.world.physics.CollisionType
|
import ru.dbotthepony.kstarbound.world.physics.CollisionType
|
||||||
import ru.dbotthepony.kstarbound.world.physics.getBlockPlatforms
|
import ru.dbotthepony.kstarbound.world.physics.getBlockPlatforms
|
||||||
import ru.dbotthepony.kstarbound.world.physics.getBlocksMarchingSquares
|
import ru.dbotthepony.kstarbound.world.physics.getBlocksMarchingSquares
|
||||||
|
import java.util.BitSet
|
||||||
import java.util.concurrent.CopyOnWriteArraySet
|
import java.util.concurrent.CopyOnWriteArraySet
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@ -31,7 +33,7 @@ import kotlin.math.min
|
|||||||
*
|
*
|
||||||
* Весь игровой мир будет измеряться в Starbound Unit'ах
|
* Весь игровой мир будет измеряться в Starbound Unit'ах
|
||||||
*/
|
*/
|
||||||
abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType, This, CellType>, CellType : Chunk<WorldType, This, CellType>.ChunkCell>(
|
abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType, This>>(
|
||||||
val world: WorldType,
|
val world: WorldType,
|
||||||
val pos: ChunkPos,
|
val pos: ChunkPos,
|
||||||
) : ICellAccess {
|
) : ICellAccess {
|
||||||
@ -67,12 +69,26 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
|
|||||||
val aabb = AABBi(pos.tile, pos.tile + Vector2i(width, height))
|
val aabb = AABBi(pos.tile, pos.tile + Vector2i(width, height))
|
||||||
val aabbd = aabb.toDoubleAABB()
|
val aabbd = aabb.toDoubleAABB()
|
||||||
|
|
||||||
// TODO: maybe fit them into "width" and "height" variables added recently?
|
protected val cells = lazy {
|
||||||
protected abstract val cells: Object2DArray<CellType>
|
Object2DArray(width, height, AbstractCell.NULL)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected val backgroundHealth = HashMap<Vector2i, TileHealth.Tile>()
|
||||||
|
protected val foregroundHealth = HashMap<Vector2i, TileHealth.Tile>()
|
||||||
|
protected val collisionCacheDirty = Boolean2DArray.allocate(width, height)
|
||||||
|
protected val collisionCache by lazy {
|
||||||
|
Object2DArray(width, height) { _, _ -> ObjectArrayList<CollisionPoly>(0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
for (x in 0 until width)
|
||||||
|
for (y in 0 until height)
|
||||||
|
collisionCacheDirty[x, y] = true
|
||||||
|
}
|
||||||
|
|
||||||
private var hasDirtyCollisions = false
|
private var hasDirtyCollisions = false
|
||||||
|
|
||||||
// bulk mark collision dirty of neighbour chunks
|
// bulk mark collision dirty of neighbour chunks as well as ours
|
||||||
protected fun signalChunkContentsUpdated() {
|
protected fun signalChunkContentsUpdated() {
|
||||||
val signalPositions = ArrayList<Vector2i>()
|
val signalPositions = ArrayList<Vector2i>()
|
||||||
|
|
||||||
@ -93,7 +109,17 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
|
|||||||
val chunk = world.chunkMap[world.geometry.chunkFromCell(actualCellPosition)] ?: continue
|
val chunk = world.chunkMap[world.geometry.chunkFromCell(actualCellPosition)] ?: continue
|
||||||
|
|
||||||
chunk.hasDirtyCollisions = true
|
chunk.hasDirtyCollisions = true
|
||||||
chunk.cells[actualCellPosition.x - chunk.pos.tileX, actualCellPosition.y - chunk.pos.tileY].collisionCacheDirty = true
|
chunk.collisionCacheDirty[actualCellPosition.x - chunk.pos.tileX, actualCellPosition.y - chunk.pos.tileY] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
hasDirtyCollisions = true
|
||||||
|
backgroundHealth.clear()
|
||||||
|
foregroundHealth.clear()
|
||||||
|
|
||||||
|
for (x in 0 until width) {
|
||||||
|
for (y in 0 until height) {
|
||||||
|
collisionCacheDirty[x, y] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +136,7 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
|
|||||||
|
|
||||||
for (x in 0 until width) {
|
for (x in 0 until width) {
|
||||||
for (y in 0 until height) {
|
for (y in 0 until height) {
|
||||||
if (cells[x, y].collisionCacheDirty) {
|
if (collisionCacheDirty[x, y]) {
|
||||||
minX = min(minX, x)
|
minX = min(minX, x)
|
||||||
minY = min(minY, y)
|
minY = min(minY, y)
|
||||||
maxX = max(maxX, x)
|
maxX = max(maxX, x)
|
||||||
@ -121,13 +147,11 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
|
|||||||
|
|
||||||
for (x in minX .. maxX) {
|
for (x in minX .. maxX) {
|
||||||
for (y in minY .. maxY) {
|
for (y in minY .. maxY) {
|
||||||
val cell = cells[x, y]
|
if (collisionCacheDirty[x, y]) {
|
||||||
|
collisionCache[x, y].clear()
|
||||||
if (cell.collisionCacheDirty) {
|
getBlocksMarchingSquares(pos.tileX + x, pos.tileY + y, world.foreground, CollisionType.DYNAMIC, collisionCache[x, y])
|
||||||
cell.collisionCache.clear()
|
getBlockPlatforms(pos.tileX + x, pos.tileY + y, world.foreground, CollisionType.PLATFORM, collisionCache[x, y])
|
||||||
getBlocksMarchingSquares(pos.tileX + x, pos.tileY + y, world.foreground, CollisionType.DYNAMIC, cell.collisionCache)
|
collisionCacheDirty[x, y] = false
|
||||||
getBlockPlatforms(pos.tileX + x, pos.tileY + y, world.foreground, CollisionType.PLATFORM, cell.collisionCache)
|
|
||||||
cell.collisionCacheDirty = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,84 +161,71 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
|
|||||||
hasDirtyCollisions = false
|
hasDirtyCollisions = false
|
||||||
}
|
}
|
||||||
|
|
||||||
target.addAll(cells[x, y].collisionCache)
|
target.addAll(collisionCache[x, y])
|
||||||
}
|
|
||||||
|
|
||||||
abstract inner class ChunkCell(val x: Int, val y: Int) {
|
|
||||||
private var actualState: ImmutableCell = AbstractCell.NULL
|
|
||||||
|
|
||||||
var state: ImmutableCell
|
|
||||||
get() = actualState
|
|
||||||
set(value) {
|
|
||||||
if (actualState != value) {
|
|
||||||
foregroundHealth.reset()
|
|
||||||
backgroundHealth.reset()
|
|
||||||
hasDirtyCollisions = true
|
|
||||||
collisionCacheDirty = true
|
|
||||||
|
|
||||||
for (xoff in -2 .. 2) {
|
|
||||||
for (yoff in -2 .. 2) {
|
|
||||||
val actualCellPosition = world.geometry.wrap(pos.tile + Vector2i(x + xoff, y + yoff))
|
|
||||||
val chunk = world.chunkMap[world.geometry.chunkFromCell(actualCellPosition)] ?: continue
|
|
||||||
|
|
||||||
chunk.hasDirtyCollisions = true
|
|
||||||
chunk.cells[actualCellPosition.x - chunk.pos.tileX, actualCellPosition.y - chunk.pos.tileY].collisionCacheDirty = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val old = actualState
|
|
||||||
actualState = value
|
|
||||||
|
|
||||||
if (old.foreground != value.foreground) {
|
|
||||||
foregroundChanges(x, y, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (old.background != value.background) {
|
|
||||||
backgroundChanges(x, y, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (old.liquid != value.liquid) {
|
|
||||||
liquidChanges(x, y, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
cellChanges(x, y, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does not trigger any change events
|
|
||||||
*/
|
|
||||||
fun setStateQuiet(state: ImmutableCell) {
|
|
||||||
foregroundHealth.reset()
|
|
||||||
backgroundHealth.reset()
|
|
||||||
hasDirtyCollisions = true
|
|
||||||
collisionCacheDirty = true
|
|
||||||
actualState = state
|
|
||||||
}
|
|
||||||
|
|
||||||
var collisionCacheDirty = true
|
|
||||||
val foregroundHealth = TileHealth.Tile()
|
|
||||||
val backgroundHealth = TileHealth.Tile()
|
|
||||||
val collisionCache = ObjectArrayList<CollisionPoly>(2) // no CME checks
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadCells(source: Object2DArray<out AbstractCell>) {
|
fun loadCells(source: Object2DArray<out AbstractCell>) {
|
||||||
val ours = cells
|
val ours = cells.value
|
||||||
source.checkSizeEquals(ours)
|
source.checkSizeEquals(ours)
|
||||||
|
|
||||||
for (x in 0 until CHUNK_SIZE) {
|
for (x in 0 until CHUNK_SIZE) {
|
||||||
for (y in 0 until CHUNK_SIZE) {
|
for (y in 0 until CHUNK_SIZE) {
|
||||||
ours[x, y].state = source[x, y].immutable()
|
ours[x, y] = source[x, y].immutable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signalChunkContentsUpdated()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun copyCells(): Object2DArray<ImmutableCell> {
|
||||||
|
if (cells.isInitialized()) {
|
||||||
|
val cells = cells.value
|
||||||
|
return Object2DArray(CHUNK_SIZE, CHUNK_SIZE) { x, y -> cells[x, y] }
|
||||||
|
} else {
|
||||||
|
return Object2DArray(CHUNK_SIZE, CHUNK_SIZE, AbstractCell.NULL)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCell(x: Int, y: Int): AbstractCell {
|
override fun getCell(x: Int, y: Int): AbstractCell {
|
||||||
return cells[x, y].state
|
return if (cells.isInitialized()) cells.value[x, y] else AbstractCell.NULL
|
||||||
}
|
}
|
||||||
|
|
||||||
final override fun setCell(x: Int, y: Int, cell: AbstractCell): Boolean {
|
final override fun setCell(x: Int, y: Int, cell: AbstractCell): Boolean {
|
||||||
cells[x, y].state = cell.immutable()
|
val old = if (cells.isInitialized()) cells.value[x, y] else AbstractCell.NULL
|
||||||
|
val new = cell.immutable()
|
||||||
|
|
||||||
|
if (old != new) {
|
||||||
|
cells.value[x, y] = new
|
||||||
|
hasDirtyCollisions = true
|
||||||
|
collisionCacheDirty[x, y] = true
|
||||||
|
|
||||||
|
for (xoff in -2 .. 2) {
|
||||||
|
for (yoff in -2 .. 2) {
|
||||||
|
val actualCellPosition = world.geometry.wrap(pos.tile + Vector2i(x + xoff, y + yoff))
|
||||||
|
val chunk = world.chunkMap[world.geometry.chunkFromCell(actualCellPosition)] ?: continue
|
||||||
|
|
||||||
|
chunk.hasDirtyCollisions = true
|
||||||
|
chunk.collisionCacheDirty[actualCellPosition.x - chunk.pos.tileX, actualCellPosition.y - chunk.pos.tileY] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old.foreground != new.foreground) {
|
||||||
|
foregroundHealth.remove(Vector2i(x, y))
|
||||||
|
foregroundChanges(x, y, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old.background != new.background) {
|
||||||
|
backgroundHealth.remove(Vector2i(x, y))
|
||||||
|
backgroundChanges(x, y, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old.liquid != new.liquid) {
|
||||||
|
liquidChanges(x, y, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
cellChanges(x, y, new)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ import java.util.random.RandomGenerator
|
|||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, ChunkType, *>>(val template: WorldTemplate) : ICellAccess {
|
abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, ChunkType>>(val template: WorldTemplate) : ICellAccess {
|
||||||
val background = TileView.Background(this)
|
val background = TileView.Background(this)
|
||||||
val foreground = TileView.Foreground(this)
|
val foreground = TileView.Foreground(this)
|
||||||
val sky = Sky(template.skyParameters)
|
val sky = Sky(template.skyParameters)
|
||||||
|
Loading…
Reference in New Issue
Block a user