little bit polishing
This commit is contained in:
parent
6302661019
commit
fd1a63a22c
@ -110,7 +110,7 @@ object Starbound : ISBFileLocator {
|
|||||||
|
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
val thread = Thread(::universeThread, "Universe")
|
val thread = Thread(::universeThread, "Universe Thread")
|
||||||
val mailbox = MailboxExecutorService(thread).also { it.exceptionHandler = ExceptionLogger(LOGGER) }
|
val mailbox = MailboxExecutorService(thread).also { it.exceptionHandler = ExceptionLogger(LOGGER) }
|
||||||
val mailboxBootstrapped = MailboxExecutorService(thread).also { it.exceptionHandler = ExceptionLogger(LOGGER) }
|
val mailboxBootstrapped = MailboxExecutorService(thread).also { it.exceptionHandler = ExceptionLogger(LOGGER) }
|
||||||
val mailboxInitialized = MailboxExecutorService(thread).also { it.exceptionHandler = ExceptionLogger(LOGGER) }
|
val mailboxInitialized = MailboxExecutorService(thread).also { it.exceptionHandler = ExceptionLogger(LOGGER) }
|
||||||
|
@ -308,10 +308,6 @@ class ClientWorld(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick0() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ring = listOf(
|
val ring = listOf(
|
||||||
Vector2i(0, 0),
|
Vector2i(0, 0),
|
||||||
|
@ -9,7 +9,6 @@ import org.apache.logging.log4j.LogManager
|
|||||||
import ru.dbotthepony.kommons.util.IStruct2i
|
import ru.dbotthepony.kommons.util.IStruct2i
|
||||||
import ru.dbotthepony.kommons.vector.Vector2d
|
import ru.dbotthepony.kommons.vector.Vector2d
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.defs.SpawnTarget
|
|
||||||
import ru.dbotthepony.kstarbound.defs.WarpAction
|
import ru.dbotthepony.kstarbound.defs.WarpAction
|
||||||
import ru.dbotthepony.kstarbound.defs.WorldID
|
import ru.dbotthepony.kstarbound.defs.WorldID
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.TileDamage
|
import ru.dbotthepony.kstarbound.defs.tile.TileDamage
|
||||||
@ -20,7 +19,6 @@ import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
|||||||
import ru.dbotthepony.kstarbound.network.IPacket
|
import ru.dbotthepony.kstarbound.network.IPacket
|
||||||
import ru.dbotthepony.kstarbound.network.packets.StepUpdatePacket
|
import ru.dbotthepony.kstarbound.network.packets.StepUpdatePacket
|
||||||
import ru.dbotthepony.kstarbound.network.packets.clientbound.PlayerWarpResultPacket
|
import ru.dbotthepony.kstarbound.network.packets.clientbound.PlayerWarpResultPacket
|
||||||
import ru.dbotthepony.kstarbound.network.packets.clientbound.WorldStopPacket
|
|
||||||
import ru.dbotthepony.kstarbound.server.StarboundServer
|
import ru.dbotthepony.kstarbound.server.StarboundServer
|
||||||
import ru.dbotthepony.kstarbound.server.ServerConnection
|
import ru.dbotthepony.kstarbound.server.ServerConnection
|
||||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||||
@ -64,14 +62,14 @@ class ServerWorld private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val players = CopyOnWriteArrayList<ServerWorldTracker>()
|
val clients = CopyOnWriteArrayList<ServerWorldTracker>()
|
||||||
|
|
||||||
private fun doAcceptClient(client: ServerConnection, action: WarpAction?) {
|
private fun doAcceptClient(client: ServerConnection, action: WarpAction?) {
|
||||||
if (players.any { it.client == client })
|
if (clients.any { it.client == client })
|
||||||
throw IllegalStateException("$client is already in $this")
|
throw IllegalStateException("$client is already in $this")
|
||||||
|
|
||||||
val start = if (action is WarpAction.Player)
|
val start = if (action is WarpAction.Player)
|
||||||
players.firstOrNull { it.client.uuid == action.uuid }?.client?.playerEntity?.position
|
clients.firstOrNull { it.client.uuid == action.uuid }?.client?.playerEntity?.position
|
||||||
else if (action is WarpAction.World)
|
else if (action is WarpAction.World)
|
||||||
action.target.resolve(this)
|
action.target.resolve(this)
|
||||||
else
|
else
|
||||||
@ -86,7 +84,7 @@ class ServerWorld private constructor(
|
|||||||
client.send(PlayerWarpResultPacket(true, action, false))
|
client.send(PlayerWarpResultPacket(true, action, false))
|
||||||
|
|
||||||
client.tracker?.remove()
|
client.tracker?.remove()
|
||||||
players.add(ServerWorldTracker(this, client, start))
|
clients.add(ServerWorldTracker(this, client, start))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun acceptClient(player: ServerConnection, action: WarpAction? = null): CompletableFuture<Unit> {
|
fun acceptClient(player: ServerConnection, action: WarpAction? = null): CompletableFuture<Unit> {
|
||||||
@ -134,7 +132,7 @@ class ServerWorld private constructor(
|
|||||||
if (isClosed.compareAndSet(false, true)) {
|
if (isClosed.compareAndSet(false, true)) {
|
||||||
super.close()
|
super.close()
|
||||||
spinner.unpause()
|
spinner.unpause()
|
||||||
players.forEach { it.remove() }
|
clients.forEach { it.remove() }
|
||||||
|
|
||||||
if (worldID != WorldID.Limbo)
|
if (worldID != WorldID.Limbo)
|
||||||
server.worlds.remove(worldID)
|
server.worlds.remove(worldID)
|
||||||
@ -180,10 +178,11 @@ class ServerWorld private constructor(
|
|||||||
return topMost
|
return topMost
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick0() {
|
override fun tick() {
|
||||||
|
super.tick()
|
||||||
val packet = StepUpdatePacket(ticks)
|
val packet = StepUpdatePacket(ticks)
|
||||||
|
|
||||||
players.forEach {
|
clients.forEach {
|
||||||
if (!isClosed.get()) {
|
if (!isClosed.get()) {
|
||||||
it.send(packet)
|
it.send(packet)
|
||||||
|
|
||||||
@ -210,7 +209,7 @@ class ServerWorld private constructor(
|
|||||||
val unloadable = entityIndex
|
val unloadable = entityIndex
|
||||||
.query(
|
.query(
|
||||||
chunk.aabb,
|
chunk.aabb,
|
||||||
predicate = Predicate { it.isApplicableForUnloading && chunk.aabb.isInside(it.position) },
|
filter = Predicate { it.isApplicableForUnloading && chunk.aabb.isInside(it.position) },
|
||||||
distinct = true, withEdges = false)
|
distinct = true, withEdges = false)
|
||||||
|
|
||||||
storage.saveCells(it.pos, chunk.copyCells())
|
storage.saveCells(it.pos, chunk.copyCells())
|
||||||
@ -230,7 +229,7 @@ class ServerWorld private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun broadcast(packet: IPacket) {
|
override fun broadcast(packet: IPacket) {
|
||||||
players.forEach {
|
clients.forEach {
|
||||||
it.send(packet)
|
it.send(packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,18 @@ class ServerWorldTracker(val world: ServerWorld, val client: ServerConnection, p
|
|||||||
return pos in tickets
|
return pos in tickets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isTracking(entity: AbstractEntity): Boolean {
|
||||||
|
return entityVersions.containsKey(entity.entityID)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun forget(entity: AbstractEntity, isDeath: Boolean = false) {
|
||||||
|
val version = entityVersions.remove(entity.entityID)
|
||||||
|
|
||||||
|
if (version != -1L) {
|
||||||
|
send(EntityDestroyPacket(entity.entityID, entity.networkGroup.write(version, isLegacy = client.isLegacy).first, isDeath))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun tick() {
|
fun tick() {
|
||||||
if (!client.worldStartAcknowledged)
|
if (!client.worldStartAcknowledged)
|
||||||
return
|
return
|
||||||
@ -245,7 +257,7 @@ class ServerWorldTracker(val world: ServerWorld, val client: ServerConnection, p
|
|||||||
if (isActuallyRemoved) return
|
if (isActuallyRemoved) return
|
||||||
|
|
||||||
isActuallyRemoved = true
|
isActuallyRemoved = true
|
||||||
world.players.remove(this)
|
world.clients.remove(this)
|
||||||
tickets.values.forEach { it.ticket.cancel() }
|
tickets.values.forEach { it.ticket.cancel() }
|
||||||
|
|
||||||
val itr = world.entities.int2ObjectEntrySet().iterator()
|
val itr = world.entities.int2ObjectEntrySet().iterator()
|
||||||
|
@ -17,6 +17,7 @@ import kotlin.concurrent.withLock
|
|||||||
|
|
||||||
// Advantages of this system include allowing to put entities outside any chunks
|
// Advantages of this system include allowing to put entities outside any chunks
|
||||||
// into index and getting rid of "orphaned entities" collection,
|
// into index and getting rid of "orphaned entities" collection,
|
||||||
|
// and allowing one entity to have multiple bounding boxes,
|
||||||
// while also setting up ground for better spatial index strategies, if they
|
// while also setting up ground for better spatial index strategies, if they
|
||||||
// have to be done in the future.
|
// have to be done in the future.
|
||||||
class SpatialIndex<T>(val geometry: WorldGeometry) {
|
class SpatialIndex<T>(val geometry: WorldGeometry) {
|
||||||
@ -242,17 +243,18 @@ class SpatialIndex<T>(val geometry: WorldGeometry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [filter] might be invoked for same entry multiple times, regardless pf [distinct]
|
* [filter] might be invoked for same entry multiple times, regardless of [distinct]
|
||||||
*/
|
*/
|
||||||
fun query(rect: AABBi, filter: Predicate<T> = Predicate { true }, distinct: Boolean = true, withEdges: Boolean = true): List<T> {
|
fun query(rect: AABBi, filter: Predicate<T> = Predicate { true }, distinct: Boolean = true, withEdges: Boolean = true): List<T> {
|
||||||
return query(rect.toDoubleAABB(), filter, distinct, withEdges)
|
return query(rect.toDoubleAABB(), filter, distinct, withEdges)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [predicate] might be invoked for same entry multiple times, regardless pf [distinct]
|
* [filter] might be invoked for same entry multiple times, regardless of [distinct]
|
||||||
*/
|
*/
|
||||||
fun query(rect: AABB, predicate: Predicate<T> = Predicate { true }, distinct: Boolean = true, withEdges: Boolean = true): List<T> {
|
fun query(rect: AABB, filter: Predicate<T> = Predicate { true }, distinct: Boolean = true, withEdges: Boolean = true): List<T> {
|
||||||
val entries = ArrayList<Entry>()
|
val entries = ArrayList<Entry>()
|
||||||
|
val entriesDirect = ArrayList<T>()
|
||||||
|
|
||||||
for (actualRegion in geometry.split(rect).first) {
|
for (actualRegion in geometry.split(rect).first) {
|
||||||
val xMin = geometry.x.chunkFromCell(actualRegion.mins.x)
|
val xMin = geometry.x.chunkFromCell(actualRegion.mins.x)
|
||||||
@ -265,9 +267,17 @@ class SpatialIndex<T>(val geometry: WorldGeometry) {
|
|||||||
for (y in yMin .. yMax) {
|
for (y in yMin .. yMax) {
|
||||||
val sector = map[index(x, y)] ?: continue
|
val sector = map[index(x, y)] ?: continue
|
||||||
|
|
||||||
for (entry in sector.entries) {
|
if (distinct) {
|
||||||
if (predicate.test(entry.value) && entry.intersects(actualRegion, withEdges)) {
|
for (entry in sector.entries) {
|
||||||
entries.add(entry)
|
if (filter.test(entry.value) && entry.intersects(actualRegion, withEdges)) {
|
||||||
|
entries.add(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (entry in sector.entries) {
|
||||||
|
if (filter.test(entry.value) && entry.intersects(actualRegion, withEdges)) {
|
||||||
|
entriesDirect.add(entry.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,10 +302,7 @@ class SpatialIndex<T>(val geometry: WorldGeometry) {
|
|||||||
|
|
||||||
return entries0
|
return entries0
|
||||||
} else {
|
} else {
|
||||||
if (entries.isEmpty())
|
return entriesDirect
|
||||||
return listOf()
|
|
||||||
|
|
||||||
return entries.map { it.value }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,7 +218,6 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
|||||||
val entities = Int2ObjectOpenHashMap<AbstractEntity>()
|
val entities = Int2ObjectOpenHashMap<AbstractEntity>()
|
||||||
val entityIndex = SpatialIndex<AbstractEntity>(geometry)
|
val entityIndex = SpatialIndex<AbstractEntity>(geometry)
|
||||||
val dynamicEntities = ArrayList<DynamicEntity>()
|
val dynamicEntities = ArrayList<DynamicEntity>()
|
||||||
val tileEntities = ArrayList<TileEntity>()
|
|
||||||
|
|
||||||
var playerSpawnPosition = Vector2d.ZERO
|
var playerSpawnPosition = Vector2d.ZERO
|
||||||
protected set
|
protected set
|
||||||
@ -252,34 +251,28 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
|||||||
check(isSameThread()) { "Trying to access $this from ${Thread.currentThread()}" }
|
check(isSameThread()) { "Trying to access $this from ${Thread.currentThread()}" }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tick() {
|
open fun tick() {
|
||||||
try {
|
ticks++
|
||||||
ticks++
|
mailbox.executeQueuedTasks()
|
||||||
mailbox.executeQueuedTasks()
|
|
||||||
|
|
||||||
Starbound.EXECUTOR.submit(ParallelPerform(dynamicEntities.spliterator(), {
|
Starbound.EXECUTOR.submit(ParallelPerform(dynamicEntities.spliterator(), {
|
||||||
if (!it.isRemote) {
|
if (!it.isRemote) {
|
||||||
it.movement.move()
|
it.movement.move()
|
||||||
}
|
|
||||||
})).join()
|
|
||||||
|
|
||||||
mailbox.executeQueuedTasks()
|
|
||||||
|
|
||||||
entities.values.forEach { it.tick() }
|
|
||||||
mailbox.executeQueuedTasks()
|
|
||||||
|
|
||||||
for (chunk in chunkMap) {
|
|
||||||
chunk.tick()
|
|
||||||
}
|
}
|
||||||
|
})).join()
|
||||||
|
|
||||||
mailbox.executeQueuedTasks()
|
mailbox.executeQueuedTasks()
|
||||||
tick0()
|
|
||||||
} catch(err: Throwable) {
|
entities.values.forEach { it.tick() }
|
||||||
throw RuntimeException("Ticking world $this", err)
|
mailbox.executeQueuedTasks()
|
||||||
|
|
||||||
|
for (chunk in chunkMap) {
|
||||||
|
chunk.tick()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mailbox.executeQueuedTasks()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun tick0()
|
|
||||||
protected abstract fun chunkFactory(pos: ChunkPos): ChunkType
|
protected abstract fun chunkFactory(pos: ChunkPos): ChunkType
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
|
@ -12,6 +12,7 @@ import ru.dbotthepony.kstarbound.defs.JsonDriven
|
|||||||
import ru.dbotthepony.kstarbound.network.packets.EntityDestroyPacket
|
import ru.dbotthepony.kstarbound.network.packets.EntityDestroyPacket
|
||||||
import ru.dbotthepony.kstarbound.network.syncher.MasterElement
|
import ru.dbotthepony.kstarbound.network.syncher.MasterElement
|
||||||
import ru.dbotthepony.kstarbound.network.syncher.NetworkedGroup
|
import ru.dbotthepony.kstarbound.network.syncher.NetworkedGroup
|
||||||
|
import ru.dbotthepony.kstarbound.server.world.ServerWorld
|
||||||
import ru.dbotthepony.kstarbound.world.LightCalculator
|
import ru.dbotthepony.kstarbound.world.LightCalculator
|
||||||
import ru.dbotthepony.kstarbound.world.SpatialIndex
|
import ru.dbotthepony.kstarbound.world.SpatialIndex
|
||||||
import ru.dbotthepony.kstarbound.world.World
|
import ru.dbotthepony.kstarbound.world.World
|
||||||
@ -109,7 +110,7 @@ abstract class AbstractEntity(path: String) : JsonDriven(path), Comparable<Abstr
|
|||||||
onJoinWorld(world)
|
onJoinWorld(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remove() {
|
fun remove(isDeath: Boolean = false) {
|
||||||
val world = innerWorld ?: throw IllegalStateException("Not in world")
|
val world = innerWorld ?: throw IllegalStateException("Not in world")
|
||||||
world.ensureSameThread()
|
world.ensureSameThread()
|
||||||
|
|
||||||
@ -119,6 +120,12 @@ abstract class AbstractEntity(path: String) : JsonDriven(path), Comparable<Abstr
|
|||||||
spatialEntry?.remove()
|
spatialEntry?.remove()
|
||||||
spatialEntry = null
|
spatialEntry = null
|
||||||
innerWorld = null
|
innerWorld = null
|
||||||
|
|
||||||
|
if (world is ServerWorld) {
|
||||||
|
world.clients.forEach {
|
||||||
|
it.forget(this, isDeath)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var isRemote: Boolean = false
|
var isRemote: Boolean = false
|
||||||
|
@ -25,11 +25,9 @@ abstract class TileEntity(path: String) : AbstractEntity(path) {
|
|||||||
get() = tilePosition.toDoubleVector()
|
get() = tilePosition.toDoubleVector()
|
||||||
|
|
||||||
override fun onJoinWorld(world: World<*, *>) {
|
override fun onJoinWorld(world: World<*, *>) {
|
||||||
world.tileEntities.add(this)
|
|
||||||
tilePosition = tilePosition
|
tilePosition = tilePosition
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRemove(world: World<*, *>) {
|
override fun onRemove(world: World<*, *>) {
|
||||||
world.tileEntities.remove(this)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user