package ru.dbotthepony.kstarbound.server import ru.dbotthepony.kommons.util.MailboxExecutorService import ru.dbotthepony.kstarbound.client.network.packets.JoinWorldPacket import ru.dbotthepony.kstarbound.server.network.ServerChannels import ru.dbotthepony.kstarbound.server.network.ServerConnection import ru.dbotthepony.kstarbound.server.world.ServerWorld import java.io.Closeable import java.io.File import java.util.Collections import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.locks.LockSupport import java.util.concurrent.locks.ReentrantLock import kotlin.concurrent.withLock sealed class StarboundServer(val root: File) : Closeable { init { if (!root.exists()) { check(root.mkdirs()) { "Unable to create ${root.absolutePath}" } } else if (!root.isDirectory) { throw IllegalArgumentException("${root.absolutePath} is not a directory") } } val worlds: MutableList = Collections.synchronizedList(ArrayList()) val serverID = threadCounter.getAndIncrement() val thread = Thread(::runThread, "Starbound Server $serverID") val mailbox = MailboxExecutorService(thread) val settings = ServerSettings() val channels = ServerChannels(this) val lock = ReentrantLock() @Volatile var isClosed = false private set init { thread.isDaemon = this is IntegratedStarboundServer thread.start() } fun playerInGame(player: ServerConnection) { val world = worlds.first() world.acceptPlayer(player) } protected abstract fun close0() private fun runThread() { while (!isClosed) { mailbox.executeQueuedTasks() LockSupport.park() } } final override fun close() { lock.withLock { if (isClosed) return channels.close() worlds.forEach { it.close() } close0() LockSupport.unpark(thread) } } companion object { private val threadCounter = AtomicInteger() } }