Some polishing
This commit is contained in:
parent
21a13134a4
commit
f452cbeeb1
@ -110,7 +110,7 @@ object Starbound : ISBFileLocator {
|
|||||||
|
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
val thread = Thread(::universeThread, "Starbound Universe")
|
val thread = Thread(::universeThread, "Universe")
|
||||||
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) }
|
||||||
|
@ -1064,7 +1064,7 @@ class StarboundClient private constructor(val clientID: Int) : Closeable {
|
|||||||
|
|
||||||
future.complete(client)
|
future.complete(client)
|
||||||
client.spin()
|
client.spin()
|
||||||
}, "Starbound Client $clientID")
|
}, "Client Thread $clientID")
|
||||||
|
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ sealed class WorldID {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "WorldID.ShipWorld[$uuid]"
|
return "WorldID.ShipWorld[${uuid.toString().substring(0, 8)}]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ abstract class Connection(val side: ConnectionSide, val type: ConnectionType) :
|
|||||||
private val legacyWarpActionCodec = StreamCodec.Pair(WarpAction.LEGACY_CODEC, WarpMode.CODEC).koptional()
|
private val legacyWarpActionCodec = StreamCodec.Pair(WarpAction.LEGACY_CODEC, WarpMode.CODEC).koptional()
|
||||||
|
|
||||||
val NIO_POOL by lazy {
|
val NIO_POOL by lazy {
|
||||||
NioEventLoopGroup(1, ThreadFactoryBuilder().setDaemon(true).setNameFormat("Starbound Network IO %d").build())
|
NioEventLoopGroup(1, ThreadFactoryBuilder().setDaemon(true).setNameFormat("Network IO %d").build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ class ServerChannels(val server: StarboundServer) : Closeable {
|
|||||||
lock.withLock {
|
lock.withLock {
|
||||||
if (isClosed) return
|
if (isClosed) return
|
||||||
|
|
||||||
connections.forEach { it.disconnect("Server is stopping") }
|
connections.forEach { it.disconnect("Server shutting down") }
|
||||||
channels.forEach { it.channel().close() }
|
channels.forEach { it.channel().close() }
|
||||||
channels.clear()
|
channels.clear()
|
||||||
connections.clear()
|
connections.clear()
|
||||||
|
@ -30,6 +30,7 @@ import kotlin.properties.Delegates
|
|||||||
class ServerConnection(val server: StarboundServer, type: ConnectionType) : Connection(ConnectionSide.SERVER, type) {
|
class ServerConnection(val server: StarboundServer, type: ConnectionType) : Connection(ConnectionSide.SERVER, type) {
|
||||||
var tracker: ServerWorldTracker? = null
|
var tracker: ServerWorldTracker? = null
|
||||||
var worldStartAcknowledged = false
|
var worldStartAcknowledged = false
|
||||||
|
var returnWarp: WarpAction? = null
|
||||||
|
|
||||||
val world: ServerWorld?
|
val world: ServerWorld?
|
||||||
get() = tracker?.world
|
get() = tracker?.world
|
||||||
@ -53,8 +54,8 @@ class ServerConnection(val server: StarboundServer, type: ConnectionType) : Conn
|
|||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
val channel = if (hasChannel) channel.remoteAddress().toString() else "<no channel>"
|
val channel = if (hasChannel) channel.remoteAddress().toString() else "<no channel>"
|
||||||
val ship = if (::shipWorld.isInitialized) shipWorld.toString() else "<no shipworld>"
|
val world = tracker?.world?.toString() ?: "<not in world>"
|
||||||
return "ServerConnection[ID=$connectionID channel=$channel / $ship]"
|
return "ServerConnection[$nickname $uuid ID=$connectionID channel=$channel / $world]"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val shipChunks = HashMap<ByteKey, KOptional<ByteArray>>()
|
private val shipChunks = HashMap<ByteKey, KOptional<ByteArray>>()
|
||||||
@ -142,6 +143,7 @@ class ServerConnection(val server: StarboundServer, type: ConnectionType) : Conn
|
|||||||
|
|
||||||
if (pendingWarp != null) {
|
if (pendingWarp != null) {
|
||||||
val (request, deploy) = pendingWarp
|
val (request, deploy) = pendingWarp
|
||||||
|
LOGGER.info("Trying to warp $this to $request")
|
||||||
|
|
||||||
val resolve = request.resolve(this)
|
val resolve = request.resolve(this)
|
||||||
|
|
||||||
@ -231,13 +233,16 @@ class ServerConnection(val server: StarboundServer, type: ConnectionType) : Conn
|
|||||||
server.channels.incrementPlayerCount()
|
server.channels.incrementPlayerCount()
|
||||||
|
|
||||||
if (isLegacy) {
|
if (isLegacy) {
|
||||||
LOGGER.info("Initializing ship world for $this")
|
|
||||||
|
|
||||||
ServerWorld.load(server, shipChunkSource, WorldID.ShipWorld(uuid!!)).thenAccept {
|
ServerWorld.load(server, shipChunkSource, WorldID.ShipWorld(uuid!!)).thenAccept {
|
||||||
shipWorld = it
|
if (!isConnected || !channel.isOpen) {
|
||||||
shipWorld.thread.start()
|
LOGGER.warn("$this disconnected before loaded their ShipWorld")
|
||||||
enqueueWarp(WarpAlias.OwnShip)
|
it.close()
|
||||||
warpingAllowed = true
|
} else {
|
||||||
|
shipWorld = it
|
||||||
|
shipWorld.thread.start()
|
||||||
|
enqueueWarp(WarpAlias.OwnShip)
|
||||||
|
warpingAllowed = true
|
||||||
|
}
|
||||||
}.exceptionally {
|
}.exceptionally {
|
||||||
LOGGER.error("Error while initializing shipworld for $this", it)
|
LOGGER.error("Error while initializing shipworld for $this", it)
|
||||||
disconnect("Error while initializing shipworld for player: $it")
|
disconnect("Error while initializing shipworld for player: $it")
|
||||||
|
@ -30,11 +30,12 @@ sealed class StarboundServer(val root: File) : Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val limboWorldIndex = AtomicInteger()
|
||||||
|
val limboWorlds = CopyOnWriteArrayList<ServerWorld>()
|
||||||
val worlds = ConcurrentHashMap<WorldID, ServerWorld>()
|
val worlds = ConcurrentHashMap<WorldID, ServerWorld>()
|
||||||
val serverID = threadCounter.getAndIncrement()
|
|
||||||
val mailbox = MailboxExecutorService().also { it.exceptionHandler = ExceptionLogger(LOGGER) }
|
val mailbox = MailboxExecutorService().also { it.exceptionHandler = ExceptionLogger(LOGGER) }
|
||||||
val spinner = ExecutionSpinner(mailbox::executeQueuedTasks, ::tick, Starbound.TIMESTEP_NANOS)
|
val spinner = ExecutionSpinner(mailbox::executeQueuedTasks, ::tick, Starbound.TIMESTEP_NANOS)
|
||||||
val thread = Thread(spinner, "Server $serverID Thread")
|
val thread = Thread(spinner, "Server Thread")
|
||||||
val universe = ServerUniverse()
|
val universe = ServerUniverse()
|
||||||
val chat = ChatHandler(this)
|
val chat = ChatHandler(this)
|
||||||
|
|
||||||
@ -117,6 +118,7 @@ sealed class StarboundServer(val root: File) : Closeable {
|
|||||||
|
|
||||||
channels.close()
|
channels.close()
|
||||||
worlds.values.forEach { it.close() }
|
worlds.values.forEach { it.close() }
|
||||||
|
limboWorlds.forEach { it.close() }
|
||||||
universe.close()
|
universe.close()
|
||||||
close0()
|
close0()
|
||||||
}
|
}
|
||||||
@ -130,7 +132,6 @@ sealed class StarboundServer(val root: File) : Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val threadCounter = AtomicInteger()
|
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ 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
|
||||||
@ -19,6 +20,7 @@ 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
|
||||||
@ -51,10 +53,14 @@ class ServerWorld private constructor(
|
|||||||
if (server.isClosed)
|
if (server.isClosed)
|
||||||
throw RuntimeException()
|
throw RuntimeException()
|
||||||
|
|
||||||
if (server.worlds.containsKey(worldID))
|
if (worldID != WorldID.Limbo) {
|
||||||
throw IllegalStateException("Duplicate world ID: $worldID")
|
if (server.worlds.containsKey(worldID))
|
||||||
|
throw IllegalStateException("Duplicate world ID: $worldID")
|
||||||
|
|
||||||
server.worlds[worldID] = this
|
server.worlds[worldID] = this
|
||||||
|
} else {
|
||||||
|
server.limboWorlds.add(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val players = CopyOnWriteArrayList<ServerWorldTracker>()
|
val players = CopyOnWriteArrayList<ServerWorldTracker>()
|
||||||
@ -96,7 +102,8 @@ class ServerWorld private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val spinner = ExecutionSpinner(mailbox::executeQueuedTasks, ::spin, Starbound.TIMESTEP_NANOS)
|
val spinner = ExecutionSpinner(mailbox::executeQueuedTasks, ::spin, Starbound.TIMESTEP_NANOS)
|
||||||
val thread = Thread(spinner, "Server World $worldID")
|
private val str = "Server World ${if (worldID == WorldID.Limbo) "limbo(${server.limboWorldIndex.getAndIncrement()})" else worldID.toString()}"
|
||||||
|
val thread = Thread(spinner, str)
|
||||||
val ticketListLock = ReentrantLock()
|
val ticketListLock = ReentrantLock()
|
||||||
|
|
||||||
private val isClosed = AtomicBoolean()
|
private val isClosed = AtomicBoolean()
|
||||||
@ -115,19 +122,25 @@ class ServerWorld private constructor(
|
|||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
if (isClosed.get())
|
if (isClosed.get())
|
||||||
return "NULL ServerWorld at $worldID"
|
return "NULL $str"
|
||||||
else
|
else
|
||||||
return "ServerWorld at $worldID"
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
if (isClosed.compareAndSet(false, true)) {
|
if (!isClosed.get())
|
||||||
LOGGER.info("Shutting down $this")
|
LOGGER.info("Shutting down $this")
|
||||||
|
|
||||||
|
if (isClosed.compareAndSet(false, true)) {
|
||||||
super.close()
|
super.close()
|
||||||
spinner.unpause()
|
spinner.unpause()
|
||||||
players.forEach { it.remove() }
|
players.forEach { it.remove() }
|
||||||
server.worlds.remove(worldID)
|
|
||||||
|
if (worldID != WorldID.Limbo)
|
||||||
|
server.worlds.remove(worldID)
|
||||||
|
else
|
||||||
|
server.limboWorlds.remove(this)
|
||||||
|
|
||||||
LockSupport.unpark(thread)
|
LockSupport.unpark(thread)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,7 +190,7 @@ class ServerWorld private constructor(
|
|||||||
try {
|
try {
|
||||||
it.tick()
|
it.tick()
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Exception while ticking player $it", err)
|
LOGGER.error("Exception while ticking player ${it.client}", err)
|
||||||
//it.disconnect("Exception while ticking player: $err")
|
//it.disconnect("Exception while ticking player: $err")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -450,7 +463,10 @@ class ServerWorld private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun load(server: StarboundServer, storage: WorldStorage, worldID: WorldID = WorldID.Limbo): CompletableFuture<ServerWorld> {
|
fun load(server: StarboundServer, storage: WorldStorage, worldID: WorldID = WorldID.Limbo): CompletableFuture<ServerWorld> {
|
||||||
|
LOGGER.info("Attempting to load world at $worldID")
|
||||||
|
|
||||||
return storage.loadMetadata().thenApply {
|
return storage.loadMetadata().thenApply {
|
||||||
|
LOGGER.info("Loading world at $worldID")
|
||||||
AssetPathStack("/") { _ ->
|
AssetPathStack("/") { _ ->
|
||||||
val meta = it.map { Starbound.gson.fromJson(it.data.content, MetadataJson::class.java) }.orThrow { NoSuchElementException("No world metadata is present") }
|
val meta = it.map { Starbound.gson.fromJson(it.data.content, MetadataJson::class.java) }.orThrow { NoSuchElementException("No world metadata is present") }
|
||||||
|
|
||||||
@ -462,6 +478,9 @@ class ServerWorld private constructor(
|
|||||||
world.protectedDungeonIDs.addAll(meta.protectedDungeonIds)
|
world.protectedDungeonIDs.addAll(meta.protectedDungeonIds)
|
||||||
world
|
world
|
||||||
}
|
}
|
||||||
|
}.exceptionally {
|
||||||
|
LOGGER.error("Error while instancing world $worldID", it)
|
||||||
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,14 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps
|
|||||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet
|
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
import ru.dbotthepony.kommons.vector.Vector2d
|
import ru.dbotthepony.kommons.vector.Vector2d
|
||||||
import ru.dbotthepony.kommons.vector.Vector2i
|
import ru.dbotthepony.kommons.vector.Vector2i
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.client.network.packets.ChunkCellsPacket
|
import ru.dbotthepony.kstarbound.client.network.packets.ChunkCellsPacket
|
||||||
|
import ru.dbotthepony.kstarbound.defs.SpawnTarget
|
||||||
|
import ru.dbotthepony.kstarbound.defs.WarpAction
|
||||||
|
import ru.dbotthepony.kstarbound.defs.WorldID
|
||||||
import ru.dbotthepony.kstarbound.network.IPacket
|
import ru.dbotthepony.kstarbound.network.IPacket
|
||||||
import ru.dbotthepony.kstarbound.network.packets.EntityCreatePacket
|
import ru.dbotthepony.kstarbound.network.packets.EntityCreatePacket
|
||||||
import ru.dbotthepony.kstarbound.network.packets.EntityUpdateSetPacket
|
import ru.dbotthepony.kstarbound.network.packets.EntityUpdateSetPacket
|
||||||
@ -18,6 +22,7 @@ import ru.dbotthepony.kstarbound.network.packets.clientbound.LegacyTileArrayUpda
|
|||||||
import ru.dbotthepony.kstarbound.network.packets.clientbound.LegacyTileUpdatePacket
|
import ru.dbotthepony.kstarbound.network.packets.clientbound.LegacyTileUpdatePacket
|
||||||
import ru.dbotthepony.kstarbound.network.packets.clientbound.TileDamageUpdatePacket
|
import ru.dbotthepony.kstarbound.network.packets.clientbound.TileDamageUpdatePacket
|
||||||
import ru.dbotthepony.kstarbound.network.packets.clientbound.WorldStartPacket
|
import ru.dbotthepony.kstarbound.network.packets.clientbound.WorldStartPacket
|
||||||
|
import ru.dbotthepony.kstarbound.network.packets.clientbound.WorldStopPacket
|
||||||
import ru.dbotthepony.kstarbound.server.ServerConnection
|
import ru.dbotthepony.kstarbound.server.ServerConnection
|
||||||
import ru.dbotthepony.kstarbound.world.ChunkPos
|
import ru.dbotthepony.kstarbound.world.ChunkPos
|
||||||
import ru.dbotthepony.kstarbound.world.IChunkListener
|
import ru.dbotthepony.kstarbound.world.IChunkListener
|
||||||
@ -34,13 +39,17 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|||||||
// allowing ServerConnection client to track ServerWorld state
|
// allowing ServerConnection client to track ServerWorld state
|
||||||
class ServerWorldTracker(val world: ServerWorld, val client: ServerConnection, playerStart: Vector2d) {
|
class ServerWorldTracker(val world: ServerWorld, val client: ServerConnection, playerStart: Vector2d) {
|
||||||
init {
|
init {
|
||||||
|
LOGGER.info("$client is joining $world")
|
||||||
|
|
||||||
client.worldStartAcknowledged = false
|
client.worldStartAcknowledged = false
|
||||||
client.tracker = this
|
client.tracker = this
|
||||||
|
client.worldID = world.worldID
|
||||||
}
|
}
|
||||||
|
|
||||||
var skyVersion = 0L
|
var skyVersion = 0L
|
||||||
|
|
||||||
private val isRemoved = AtomicBoolean()
|
private val isRemoved = AtomicBoolean()
|
||||||
|
private var isActuallyRemoved = false
|
||||||
private val tickets = HashMap<ChunkPos, Ticket>()
|
private val tickets = HashMap<ChunkPos, Ticket>()
|
||||||
private val pendingSend = ObjectLinkedOpenHashSet<ChunkPos>()
|
private val pendingSend = ObjectLinkedOpenHashSet<ChunkPos>()
|
||||||
private val tasks = ConcurrentLinkedQueue<ServerWorld.() -> Unit>()
|
private val tasks = ConcurrentLinkedQueue<ServerWorld.() -> Unit>()
|
||||||
@ -55,7 +64,8 @@ class ServerWorldTracker(val world: ServerWorld, val client: ServerConnection, p
|
|||||||
// packets which interact with world must be
|
// packets which interact with world must be
|
||||||
// executed on world's thread
|
// executed on world's thread
|
||||||
fun enqueue(task: ServerWorld.() -> Unit) {
|
fun enqueue(task: ServerWorld.() -> Unit) {
|
||||||
tasks.add(task)
|
if (!isRemoved.get())
|
||||||
|
tasks.add(task)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class Ticket(val ticket: ServerWorld.ITicket, val pos: ChunkPos) : IChunkListener {
|
private inner class Ticket(val ticket: ServerWorld.ITicket, val pos: ChunkPos) : IChunkListener {
|
||||||
@ -109,14 +119,21 @@ class ServerWorldTracker(val world: ServerWorld, val client: ServerConnection, p
|
|||||||
return
|
return
|
||||||
|
|
||||||
if (!client.channel.isOpen) {
|
if (!client.channel.isOpen) {
|
||||||
remove() // ???
|
// ???
|
||||||
|
remove()
|
||||||
|
remove0()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRemoved.get()) {
|
||||||
|
remove0()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
run {
|
run {
|
||||||
var next = tasks.poll()
|
var next = tasks.poll()
|
||||||
|
|
||||||
while (next != null) {
|
while (next != null && !isRemoved.get()) {
|
||||||
next.invoke(world)
|
next.invoke(world)
|
||||||
next = tasks.poll()
|
next = tasks.poll()
|
||||||
}
|
}
|
||||||
@ -194,22 +211,41 @@ class ServerWorldTracker(val world: ServerWorld, val client: ServerConnection, p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remove() {
|
private fun remove0() {
|
||||||
if (isRemoved.compareAndSet(false, true)) {
|
if (isActuallyRemoved) return
|
||||||
client.tracker = null
|
|
||||||
client.playerEntity = null
|
|
||||||
world.players.remove(this)
|
|
||||||
tickets.values.forEach { it.ticket.cancel() }
|
|
||||||
|
|
||||||
world.mailbox.execute {
|
isActuallyRemoved = true
|
||||||
val itr = world.entities.int2ObjectEntrySet().iterator()
|
world.players.remove(this)
|
||||||
|
tickets.values.forEach { it.ticket.cancel() }
|
||||||
|
|
||||||
for ((id, entity) in itr) {
|
val itr = world.entities.int2ObjectEntrySet().iterator()
|
||||||
if (id in client.entityIDRange) {
|
|
||||||
entity.remove()
|
for ((id, entity) in itr) {
|
||||||
}
|
if (id in client.entityIDRange) {
|
||||||
}
|
entity.remove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun remove() {
|
||||||
|
if (isRemoved.compareAndSet(false, true)) {
|
||||||
|
// erase all tasks just to be sure
|
||||||
|
tasks.clear()
|
||||||
|
|
||||||
|
val playerEntity = client.playerEntity
|
||||||
|
|
||||||
|
if (playerEntity != null) {
|
||||||
|
client.returnWarp = WarpAction.World(world.worldID, SpawnTarget.Position(playerEntity.position))
|
||||||
|
}
|
||||||
|
|
||||||
|
client.tracker = null
|
||||||
|
client.playerEntity = null
|
||||||
|
client.worldID = WorldID.Limbo
|
||||||
|
client.send(WorldStopPacket("Removed"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ data class UniversePos(val location: Vector3i = Vector3i.ZERO, val planetOrbit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "UniversePos[$location, planetOrbit=$planetOrbit, satelliteOrbit=$satelliteOrbit]"
|
return "${location.x},${location.y}${location.z}:$planetOrbit:$satelliteOrbit"
|
||||||
}
|
}
|
||||||
|
|
||||||
val isSystem: Boolean
|
val isSystem: Boolean
|
||||||
|
Loading…
Reference in New Issue
Block a user