Archived
1
0
Fork 0

Add ticker for suspending coroutines for a specific amount of ticks

This commit is contained in:
Moritz Ruth 2020-09-07 00:17:55 +02:00
parent 0725df25c8
commit 058c3b19be
No known key found for this signature in database
GPG key ID: AFD57E23E753841B
13 changed files with 96 additions and 19 deletions

View file

@ -41,6 +41,9 @@ dependencies {
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions.freeCompilerArgs = listOf(
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi"
)
}
compileTestKotlin {

View file

@ -9,6 +9,9 @@ import space.blokk.utils.UUIDAdapter
import space.blokk.utils.UUIDWithoutHyphensAdapter
interface BlokkProvider {
/**
* The [Server] instance.
*/
val server: Server
/**

View file

@ -1,11 +1,11 @@
package space.blokk.net.protocols.play
import io.netty.buffer.ByteBuf
import space.blokk.GameMode
import space.blokk.net.MinecraftDataTypes.writeString
import space.blokk.net.MinecraftDataTypes.writeVarInt
import space.blokk.net.protocols.OutgoingPacket
import space.blokk.net.protocols.OutgoingPacketCompanion
import space.blokk.players.GameMode
import space.blokk.worlds.WorldDimension
import space.blokk.worlds.WorldType

View file

@ -1,4 +1,4 @@
package space.blokk
package space.blokk.players
enum class GameMode {
SURVIVAL,

View file

@ -1,6 +1,7 @@
package space.blokk.server
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.ReceiveChannel
import space.blokk.events.EventBus
import space.blokk.events.EventTarget
import space.blokk.server.events.ServerEvent
@ -8,4 +9,10 @@ import space.blokk.server.events.ServerEvent
interface Server : EventTarget<ServerEvent> {
override val eventBus: EventBus<ServerEvent>
val scope: CoroutineScope
fun createTickChannel(): ReceiveChannel<Unit>
companion object {
const val TICKS_PER_SECOND = 20
}
}

View file

@ -0,0 +1,17 @@
package space.blokk.utils
import space.blokk.Blokk
/**
* Suspends for [ticks].
*/
suspend fun delayTicks(ticks: Long) {
val channel = Blokk.server.createTickChannel()
(0..ticks).forEach { _ -> channel.receive() }
channel.cancel()
}
/**
* Suspends for one tick.
*/
suspend fun delayTick() = delayTicks(1)

View file

@ -0,0 +1,16 @@
package space.blokk.worlds
/**
* A minecraft world, sometimes also called level.
*/
interface World {
/**
* The [dimension][WorldDimension] of the world.
*/
var dimension: WorldDimension
/**
* The [type][WorldType] of the world.
*/
var type: WorldType
}

View file

@ -48,6 +48,9 @@ dependencies {
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions.freeCompilerArgs = listOf(
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi"
)
}
shadowJar {

View file

@ -17,6 +17,7 @@ import space.blokk.net.events.ServerListInfoRequestEvent
import space.blokk.server.Server
import space.blokk.server.events.ServerEvent
import space.blokk.utils.EncryptionUtils
import space.blokk.utils.Ticker
import java.io.File
import java.security.KeyPair
import kotlin.system.exitProcess
@ -28,7 +29,8 @@ class BlokkServer internal constructor() : Server {
override val scope = CoroutineScope(CoroutineName("BlokkServer"))
override val eventBus = EventBus(ServerEvent::class, scope)
val logger = Logger("BlokkServer")
val logger = Logger("Server")
var socketServer = BlokkSocketServer(); private set
val keyPair: KeyPair
@ -64,7 +66,14 @@ class BlokkServer internal constructor() : Server {
)
.build().loadConfigOrThrow<BlokkConfig>()
private val ticker = Ticker(scope)
override fun createTickChannel() = ticker.createTickChannel()
init {
setProvider()
}
private fun setProvider() {
val providerField = Blokk::class.java.getDeclaredField("provider")
providerField.isAccessible = true
providerField.set(Blokk, object : BlokkProvider {
@ -86,6 +95,8 @@ class BlokkServer internal constructor() : Server {
socketServer.bind()
logger info "Listening on ${config.host}:${config.port}"
ticker.start()
}
companion object {

View file

@ -2,7 +2,6 @@ package space.blokk.net
import io.netty.buffer.Unpooled
import space.blokk.BlokkServer
import space.blokk.GameMode
import space.blokk.chat.TextComponent
import space.blokk.net.MinecraftDataTypes.writeString
import space.blokk.net.protocols.login.EncryptionRequestPacket
@ -13,6 +12,7 @@ import space.blokk.net.protocols.play.JoinGamePacket
import space.blokk.net.protocols.play.PlayProtocol
import space.blokk.net.protocols.play.PlayerAbilitiesPacket
import space.blokk.net.protocols.play.ServerDifficultyPacket
import space.blokk.players.GameMode
import space.blokk.utils.AuthenticationHelper
import space.blokk.utils.EncryptionUtils
import space.blokk.worlds.WorldDifficulty

View file

@ -0,0 +1,32 @@
package space.blokk.utils
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.ReceiveChannel
import space.blokk.server.Server
import java.util.*
import java.util.concurrent.Executors
class Ticker(serverScope: CoroutineScope) {
private val scope = serverScope + Executors
.newSingleThreadExecutor { Thread(it).also { thread -> thread.name = "Ticker" } }
.asCoroutineDispatcher()
private val channels: MutableSet<Channel<Unit>> = Collections.synchronizedSet(mutableSetOf<Channel<Unit>>())
fun createTickChannel(): ReceiveChannel<Unit> {
return Channel<Unit>().also { channel ->
channel.invokeOnClose { channels.remove(channel) }
channels.add(channel)
}
}
fun start() {
scope.launch {
while (true) {
channels.toSet().forEach { it.send(Unit) }
delay(1000L / Server.TICKS_PER_SECOND)
}
}
}
}

View file

@ -9,17 +9,3 @@ version = "0.0.1"
repositories {
mavenCentral()
}
dependencies {
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}

View file

@ -3,7 +3,6 @@ pluginManagement {
mavenCentral()
gradlePluginPortal()
}
}
rootProject.name = "blokk"