Circular world test
This commit is contained in:
parent
51a43d70be
commit
2653d043a9
@ -190,7 +190,7 @@ fun main() {
|
|||||||
client.gl.box2dRenderer.drawAABB = false
|
client.gl.box2dRenderer.drawAABB = false
|
||||||
client.gl.box2dRenderer.drawJoints = false
|
client.gl.box2dRenderer.drawJoints = false
|
||||||
|
|
||||||
ent.spawn()
|
//ent.spawn()
|
||||||
|
|
||||||
client.input.addScrollCallback { _, x, y ->
|
client.input.addScrollCallback { _, x, y ->
|
||||||
if (y > 0.0) {
|
if (y > 0.0) {
|
||||||
@ -207,11 +207,11 @@ fun main() {
|
|||||||
//client.camera.pos.x = ent.position.x.toFloat()
|
//client.camera.pos.x = ent.position.x.toFloat()
|
||||||
//client.camera.pos.y = ent.position.y.toFloat()
|
//client.camera.pos.y = ent.position.y.toFloat()
|
||||||
|
|
||||||
client.camera.pos.x += if (client.input.KEY_LEFT_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
client.camera.pos.x += if (client.input.KEY_LEFT_DOWN || client.input.KEY_A_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||||
client.camera.pos.x += if (client.input.KEY_RIGHT_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
client.camera.pos.x += if (client.input.KEY_RIGHT_DOWN || client.input.KEY_D_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||||
|
|
||||||
client.camera.pos.y += if (client.input.KEY_UP_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
client.camera.pos.y += if (client.input.KEY_UP_DOWN || client.input.KEY_W_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||||
client.camera.pos.y += if (client.input.KEY_DOWN_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
client.camera.pos.y += if (client.input.KEY_DOWN_DOWN || client.input.KEY_S_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||||
|
|
||||||
//println(client.camera.velocity.toDoubleVector() * client.frameRenderTime * 0.1)
|
//println(client.camera.velocity.toDoubleVector() * client.frameRenderTime * 0.1)
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import java.io.Closeable
|
|||||||
*/
|
*/
|
||||||
const val Z_LEVEL_BACKGROUND = 60000
|
const val Z_LEVEL_BACKGROUND = 60000
|
||||||
|
|
||||||
class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, ClientChunk>(world, pos), Closeable, ILayeredRenderer {
|
class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, ClientChunk>(world, pos), Closeable {
|
||||||
val state: GLStateTracker get() = world.client.gl
|
val state: GLStateTracker get() = world.client.gl
|
||||||
|
|
||||||
private inner class TileLayerRenderer(private val layerChangeset: () -> Int, private val isBackground: Boolean) : AutoCloseable {
|
private inner class TileLayerRenderer(private val layerChangeset: () -> Int, private val isBackground: Boolean) : AutoCloseable {
|
||||||
@ -221,63 +221,69 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val layerQueue = ArrayDeque<Pair<(Matrix4fStack) -> Unit, Int>>()
|
/**
|
||||||
|
* Хранит состояние отрисовки этого чанка
|
||||||
|
*
|
||||||
|
* Должен быть использован только один раз, после выкинут, иначе поведение
|
||||||
|
* кода невозможно будет предсказать
|
||||||
|
*/
|
||||||
|
inner class BakedLayeredRenderer constructor(val origin: ChunkPos = pos) : ILayeredRenderer {
|
||||||
|
private val layerQueue = ArrayDeque<Pair<(Matrix4fStack) -> Unit, Int>>()
|
||||||
|
|
||||||
override fun renderLayerFromStack(zPos: Int, stack: Matrix4fStack): Int {
|
init {
|
||||||
if (layerQueue.isEmpty())
|
for ((baked, zLevel) in backgroundRenderer.bakedMeshes) {
|
||||||
return -1
|
layerQueue.add(baked::renderStacked to (zLevel + Z_LEVEL_BACKGROUND))
|
||||||
|
}
|
||||||
|
|
||||||
stack.push().translateWithMultiplication(x = pos.x * CHUNK_SIZEf, y = pos.y * CHUNK_SIZEf)
|
for ((baked, zLevel) in foregroundRenderer.bakedMeshes) {
|
||||||
var pair = layerQueue.last()
|
layerQueue.add(baked::renderStacked to zLevel)
|
||||||
|
}
|
||||||
|
|
||||||
while (pair.second >= zPos) {
|
for (renderer in entityRenderers.values) {
|
||||||
pair.first.invoke(stack)
|
layerQueue.add(lambda@{ it: Matrix4fStack ->
|
||||||
|
val relative = renderer.renderPos - posVector2d
|
||||||
|
it.push().translateWithMultiplication(relative.x.toFloat(), relative.y.toFloat())
|
||||||
|
renderer.render(it)
|
||||||
|
it.pop()
|
||||||
|
return@lambda
|
||||||
|
} to renderer.layer)
|
||||||
|
}
|
||||||
|
|
||||||
layerQueue.removeLast()
|
layerQueue.sortBy {
|
||||||
|
return@sortBy it.second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renderLayerFromStack(zPos: Int, stack: Matrix4fStack): Int {
|
||||||
|
if (layerQueue.isEmpty())
|
||||||
|
return -1
|
||||||
|
|
||||||
|
stack.push().translateWithMultiplication(x = origin.x * CHUNK_SIZEf, y = origin.y * CHUNK_SIZEf)
|
||||||
|
var pair = layerQueue.last()
|
||||||
|
|
||||||
|
while (pair.second >= zPos) {
|
||||||
|
pair.first.invoke(stack)
|
||||||
|
|
||||||
|
layerQueue.removeLast()
|
||||||
|
|
||||||
|
if (layerQueue.isEmpty()) {
|
||||||
|
stack.pop()
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
pair = layerQueue.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.pop()
|
||||||
|
return layerQueue.last().second
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bottomMostZLevel(): Int {
|
||||||
if (layerQueue.isEmpty()) {
|
if (layerQueue.isEmpty()) {
|
||||||
stack.pop()
|
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
pair = layerQueue.last()
|
return layerQueue.last().second
|
||||||
}
|
|
||||||
|
|
||||||
stack.pop()
|
|
||||||
return layerQueue.last().second
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun bottomMostZLevel(): Int {
|
|
||||||
if (layerQueue.isEmpty()) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
return layerQueue.last().second
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun prepareForLayeredRender() {
|
|
||||||
layerQueue.clear()
|
|
||||||
|
|
||||||
for ((baked, zLevel) in backgroundRenderer.bakedMeshes) {
|
|
||||||
layerQueue.add(baked::renderStacked to (zLevel + Z_LEVEL_BACKGROUND))
|
|
||||||
}
|
|
||||||
|
|
||||||
for ((baked, zLevel) in foregroundRenderer.bakedMeshes) {
|
|
||||||
layerQueue.add(baked::renderStacked to zLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (renderer in entityRenderers.values) {
|
|
||||||
layerQueue.add(lambda@{ it: Matrix4fStack ->
|
|
||||||
val relative = renderer.renderPos - posVector2d
|
|
||||||
it.push().translateWithMultiplication(relative.x.toFloat(), relative.y.toFloat())
|
|
||||||
renderer.render(it)
|
|
||||||
it.pop()
|
|
||||||
return@lambda
|
|
||||||
} to renderer.layer)
|
|
||||||
}
|
|
||||||
|
|
||||||
layerQueue.sortBy {
|
|
||||||
return@sortBy it.second
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,15 +3,21 @@ package ru.dbotthepony.kstarbound.client
|
|||||||
import org.lwjgl.opengl.GL46.*
|
import org.lwjgl.opengl.GL46.*
|
||||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||||
import ru.dbotthepony.kstarbound.client.gl.VertexTransformers
|
import ru.dbotthepony.kstarbound.client.gl.VertexTransformers
|
||||||
|
import ru.dbotthepony.kstarbound.client.render.ILayeredRenderer
|
||||||
import ru.dbotthepony.kstarbound.client.render.renderLayeredList
|
import ru.dbotthepony.kstarbound.client.render.renderLayeredList
|
||||||
import ru.dbotthepony.kstarbound.defs.ParallaxPrototype
|
import ru.dbotthepony.kstarbound.defs.ParallaxPrototype
|
||||||
import ru.dbotthepony.kstarbound.math.encasingChunkPosAABB
|
import ru.dbotthepony.kstarbound.math.encasingChunkPosAABB
|
||||||
import ru.dbotthepony.kstarbound.util.DoubleEdgeProgression
|
import ru.dbotthepony.kstarbound.util.DoubleEdgeProgression
|
||||||
import ru.dbotthepony.kstarbound.world.*
|
import ru.dbotthepony.kstarbound.world.*
|
||||||
import ru.dbotthepony.kstarbound.world.entities.Entity
|
import ru.dbotthepony.kstarbound.world.entities.Entity
|
||||||
|
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||||
import ru.dbotthepony.kvector.util2d.AABB
|
import ru.dbotthepony.kvector.util2d.AABB
|
||||||
|
|
||||||
class ClientWorld(val client: StarboundClient, seed: Long = 0L) : World<ClientWorld, ClientChunk>(seed) {
|
class ClientWorld(
|
||||||
|
val client: StarboundClient,
|
||||||
|
seed: Long,
|
||||||
|
widthInChunks: Int,
|
||||||
|
) : World<ClientWorld, ClientChunk>(seed, widthInChunks) {
|
||||||
init {
|
init {
|
||||||
physics.debugDraw = client.gl.box2dRenderer
|
physics.debugDraw = client.gl.box2dRenderer
|
||||||
}
|
}
|
||||||
@ -94,20 +100,20 @@ class ClientWorld(val client: StarboundClient, seed: Long = 0L) : World<ClientWo
|
|||||||
client.gl.matrixStack.pop()
|
client.gl.matrixStack.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
val determineRenderers = ArrayList<ClientChunk>()
|
val determineRenderers = ArrayList<ILayeredRenderer>()
|
||||||
|
|
||||||
for (chunk in collect(size.encasingChunkPosAABB())) {
|
for (chunk in collectPositionAware(size.encasingChunkPosAABB())) {
|
||||||
determineRenderers.add(chunk)
|
determineRenderers.add(chunk.second.BakedLayeredRenderer(chunk.first))
|
||||||
chunk.bake()
|
chunk.second.bake()
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLayeredList(client.gl.matrixStack, determineRenderers)
|
renderLayeredList(client.gl.matrixStack, determineRenderers)
|
||||||
|
|
||||||
physics.debugDraw()
|
physics.debugDraw()
|
||||||
|
|
||||||
for (renderer in determineRenderers) {
|
/*for (renderer in determineRenderers) {
|
||||||
renderer.renderDebug()
|
renderer.renderDebug()
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun thinkInner(delta: Double) {
|
override fun thinkInner(delta: Double) {
|
||||||
|
@ -125,7 +125,7 @@ class StarboundClient : AutoCloseable {
|
|||||||
|
|
||||||
val gl = GLStateTracker()
|
val gl = GLStateTracker()
|
||||||
|
|
||||||
var world: ClientWorld? = ClientWorld(this, 0L)
|
var world: ClientWorld? = ClientWorld(this, 0L, 0)
|
||||||
|
|
||||||
fun ensureSameThread() = gl.ensureSameThread()
|
fun ensureSameThread() = gl.ensureSameThread()
|
||||||
|
|
||||||
|
@ -34,13 +34,6 @@ interface ILayeredRenderer {
|
|||||||
* если этот объект имеет самый дальний слой
|
* если этот объект имеет самый дальний слой
|
||||||
*/
|
*/
|
||||||
fun bottomMostZLevel(): Int
|
fun bottomMostZLevel(): Int
|
||||||
|
|
||||||
/**
|
|
||||||
* Говорит о том, что вот-вот будет начата отрисовка в render pipeline
|
|
||||||
* и будут вызываться [renderLayerFromStack]. В данном методе должна построиться
|
|
||||||
* и отсортироваться стопка слоёв
|
|
||||||
*/
|
|
||||||
fun prepareForLayeredRender()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun renderLayeredList(transform: Matrix4fStack, potentialRenderers: List<ILayeredRenderer>): Int {
|
fun renderLayeredList(transform: Matrix4fStack, potentialRenderers: List<ILayeredRenderer>): Int {
|
||||||
@ -48,7 +41,6 @@ fun renderLayeredList(transform: Matrix4fStack, potentialRenderers: List<ILayere
|
|||||||
var bottomMost = -1
|
var bottomMost = -1
|
||||||
|
|
||||||
for (render in potentialRenderers) {
|
for (render in potentialRenderers) {
|
||||||
render.prepareForLayeredRender()
|
|
||||||
val zLevel = render.bottomMostZLevel()
|
val zLevel = render.bottomMostZLevel()
|
||||||
|
|
||||||
if (zLevel >= 0) {
|
if (zLevel >= 0) {
|
||||||
|
@ -6,6 +6,18 @@ import ru.dbotthepony.kvector.api.IStruct2i
|
|||||||
import ru.dbotthepony.kvector.vector.nint.Vector2i
|
import ru.dbotthepony.kvector.vector.nint.Vector2i
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
|
private fun circulate(value: Int, bounds: Int): Int {
|
||||||
|
require(bounds > 0) { "Bounds must be positive ($bounds given)" }
|
||||||
|
|
||||||
|
if (value >= bounds) {
|
||||||
|
return value % bounds
|
||||||
|
} else if (value < 0) {
|
||||||
|
return bounds + value % bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сетка чанков идёт как и сетка тайлов.
|
* Сетка чанков идёт как и сетка тайлов.
|
||||||
*
|
*
|
||||||
@ -85,6 +97,16 @@ class ChunkPos(val x: Int, val y: Int) : Comparable<ChunkPos> {
|
|||||||
return y.compareTo(other.y)
|
return y.compareTo(other.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun circular(xWrap: Int): ChunkPos {
|
||||||
|
val x = circulate(x, xWrap)
|
||||||
|
|
||||||
|
if (x == this.x) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChunkPos(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ZERO = ChunkPos(0, 0)
|
val ZERO = ChunkPos(0, 0)
|
||||||
|
|
||||||
@ -93,15 +115,29 @@ class ChunkPos(val x: Int, val y: Int) : Comparable<ChunkPos> {
|
|||||||
return ChunkPos(tileToChunkComponent(x), tileToChunkComponent(y))
|
return ChunkPos(tileToChunkComponent(x), tileToChunkComponent(y))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun fromTilePosition(input: IStruct2i, xWrap: Int): ChunkPos {
|
||||||
|
val (x, y) = input
|
||||||
|
return ChunkPos(circulate(tileToChunkComponent(x), xWrap), tileToChunkComponent(y))
|
||||||
|
}
|
||||||
|
|
||||||
fun fromTilePosition(input: IStruct2d): ChunkPos {
|
fun fromTilePosition(input: IStruct2d): ChunkPos {
|
||||||
val (x, y) = input
|
val (x, y) = input
|
||||||
return fromTilePosition(x, y)
|
return fromTilePosition(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun fromTilePosition(input: IStruct2d, xWrap: Int): ChunkPos {
|
||||||
|
val (x, y) = input
|
||||||
|
return fromTilePosition(x, y, xWrap)
|
||||||
|
}
|
||||||
|
|
||||||
fun fromTilePosition(x: Int, y: Int): ChunkPos {
|
fun fromTilePosition(x: Int, y: Int): ChunkPos {
|
||||||
return ChunkPos(tileToChunkComponent(x), tileToChunkComponent(y))
|
return ChunkPos(tileToChunkComponent(x), tileToChunkComponent(y))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun fromTilePosition(x: Int, y: Int, xWrap: Int): ChunkPos {
|
||||||
|
return ChunkPos(circulate(tileToChunkComponent(x), xWrap), tileToChunkComponent(y))
|
||||||
|
}
|
||||||
|
|
||||||
fun fromTilePosition(x: Double, y: Double): ChunkPos {
|
fun fromTilePosition(x: Double, y: Double): ChunkPos {
|
||||||
return ChunkPos(
|
return ChunkPos(
|
||||||
tileToChunkComponent(roundByAbsoluteValue(x)),
|
tileToChunkComponent(roundByAbsoluteValue(x)),
|
||||||
@ -109,6 +145,13 @@ class ChunkPos(val x: Int, val y: Int) : Comparable<ChunkPos> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun fromTilePosition(x: Double, y: Double, xWrap: Int): ChunkPos {
|
||||||
|
return ChunkPos(
|
||||||
|
circulate(tileToChunkComponent(roundByAbsoluteValue(x)), xWrap),
|
||||||
|
tileToChunkComponent(roundByAbsoluteValue(y))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun normalizeCoordinate(input: Int): Int {
|
fun normalizeCoordinate(input: Int): Int {
|
||||||
val band = input and CHUNK_SIZE_FF
|
val band = input and CHUNK_SIZE_FF
|
||||||
|
|
||||||
|
@ -33,11 +33,23 @@ data class WorldSweepResult(
|
|||||||
|
|
||||||
private const val EPSILON = 0.00001
|
private const val EPSILON = 0.00001
|
||||||
|
|
||||||
abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, ChunkType>>(val seed: Long = 0L) {
|
abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, ChunkType>>(
|
||||||
|
val seed: Long,
|
||||||
|
val widthInChunks: Int
|
||||||
|
) {
|
||||||
protected val chunkMap = Object2ObjectAVLTreeMap<ChunkPos, ChunkType> cmp@{ a, b ->
|
protected val chunkMap = Object2ObjectAVLTreeMap<ChunkPos, ChunkType> cmp@{ a, b ->
|
||||||
return@cmp a.compareTo(b)
|
return@cmp a.compareTo(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Является ли мир "сферическим"
|
||||||
|
*
|
||||||
|
* Данный флаг говорит о том, что [widthInChunks] имеет осмысленное значение,
|
||||||
|
* попытка получить чанк с X координатой меньше нуля или больше [widthInChunks]
|
||||||
|
* приведёт к замыканию на конец/начало мира соответственно
|
||||||
|
*/
|
||||||
|
val isCircular = widthInChunks > 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Chunks, which have their collision mesh changed
|
* Chunks, which have their collision mesh changed
|
||||||
*/
|
*/
|
||||||
@ -213,13 +225,28 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
|||||||
* Возвращает чанк на указанной позиции если он существует
|
* Возвращает чанк на указанной позиции если он существует
|
||||||
*/
|
*/
|
||||||
open operator fun get(pos: ChunkPos): ChunkType? {
|
open operator fun get(pos: ChunkPos): ChunkType? {
|
||||||
|
if (!isCircular) {
|
||||||
|
val lastAccessedChunk = lastAccessedChunk
|
||||||
|
|
||||||
|
if (lastAccessedChunk?.pos == pos) {
|
||||||
|
return lastAccessedChunk
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunkMap[pos]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("Name_Shadowing")
|
||||||
|
val pos = pos.circular(widthInChunks)
|
||||||
|
|
||||||
val lastAccessedChunk = lastAccessedChunk
|
val lastAccessedChunk = lastAccessedChunk
|
||||||
|
|
||||||
if (lastAccessedChunk?.pos == pos) {
|
if (lastAccessedChunk?.pos == pos) {
|
||||||
return lastAccessedChunk
|
return lastAccessedChunk
|
||||||
}
|
}
|
||||||
|
|
||||||
return chunkMap[pos]
|
val load = chunkMap[pos]
|
||||||
|
this.lastAccessedChunk = load
|
||||||
|
return load
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun getInstantTuple(pos: ChunkPos): IWorldChunkTuple<This, ChunkType>? {
|
open fun getInstantTuple(pos: ChunkPos): IWorldChunkTuple<This, ChunkType>? {
|
||||||
@ -230,6 +257,9 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
|||||||
* Возвращает чанк на заданной позиции, создаёт его если он не существует
|
* Возвращает чанк на заданной позиции, создаёт его если он не существует
|
||||||
*/
|
*/
|
||||||
open fun computeIfAbsent(pos: ChunkPos): ChunkType {
|
open fun computeIfAbsent(pos: ChunkPos): ChunkType {
|
||||||
|
@Suppress("Name_Shadowing")
|
||||||
|
val pos = pos.circular(widthInChunks)
|
||||||
|
|
||||||
val _lastAccessedChunk = lastAccessedChunk
|
val _lastAccessedChunk = lastAccessedChunk
|
||||||
|
|
||||||
if (_lastAccessedChunk?.pos == pos) {
|
if (_lastAccessedChunk?.pos == pos) {
|
||||||
@ -244,7 +274,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
|||||||
val orphanedInThisChunk = ArrayList<Entity>()
|
val orphanedInThisChunk = ArrayList<Entity>()
|
||||||
|
|
||||||
for (ent in orphanedEntities) {
|
for (ent in orphanedEntities) {
|
||||||
val cPos = ChunkPos.fromTilePosition(ent.position)
|
val cPos = if (isCircular) ChunkPos.fromTilePosition(ent.position, widthInChunks) else ChunkPos.fromTilePosition(ent.position)
|
||||||
|
|
||||||
if (cPos == pos) {
|
if (cPos == pos) {
|
||||||
orphanedInThisChunk.add(ent)
|
orphanedInThisChunk.add(ent)
|
||||||
@ -330,6 +360,23 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
|||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает все чанки, которые пересекаются с заданным [boundingBox]
|
||||||
|
*/
|
||||||
|
open fun collectPositionAware(boundingBox: AABBi): List<Pair<ChunkPos, ChunkType>> {
|
||||||
|
val output = ArrayList<Pair<ChunkPos, ChunkType>>()
|
||||||
|
|
||||||
|
for (pos in boundingBox.chunkPositions) {
|
||||||
|
val chunk = get(pos)
|
||||||
|
|
||||||
|
if (chunk != null) {
|
||||||
|
output.add(pos to chunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Производит проверку на пересечение [worldaabb] с геометрией мира при попытке пройти в [_deltaMovement]
|
* Производит проверку на пересечение [worldaabb] с геометрией мира при попытке пройти в [_deltaMovement]
|
||||||
*/
|
*/
|
||||||
|
@ -95,10 +95,10 @@ abstract class Entity(override val world: World<*, *>) : IEntity {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val chunkPos = ChunkPos.fromTilePosition(position)
|
val chunkPos = if (world.isCircular) ChunkPos.fromTilePosition(position, world.widthInChunks) else ChunkPos.fromTilePosition(position)
|
||||||
|
|
||||||
if (value != null && chunkPos != value.pos) {
|
if (value != null && chunkPos != value.pos) {
|
||||||
throw IllegalStateException("Set proper position before setting chunk this Entity belongs to")
|
throw IllegalStateException("Set proper position before setting chunk this Entity belongs to (expected chunk $chunkPos, got chunk ${value.pos})")
|
||||||
}
|
}
|
||||||
|
|
||||||
val oldChunk = field
|
val oldChunk = field
|
||||||
|
Loading…
Reference in New Issue
Block a user