diff --git a/blokk-api/build.gradle.kts b/blokk-api/build.gradle.kts index 15d97c7..ec2c846 100644 --- a/blokk-api/build.gradle.kts +++ b/blokk-api/build.gradle.kts @@ -41,6 +41,9 @@ dependencies { tasks { compileKotlin { kotlinOptions.jvmTarget = "1.8" + kotlinOptions.freeCompilerArgs = listOf( + "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" + ) } compileTestKotlin { diff --git a/blokk-api/src/main/kotlin/space/blokk/Blokk.kt b/blokk-api/src/main/kotlin/space/blokk/Blokk.kt index ead5aba..4d2c6a1 100644 --- a/blokk-api/src/main/kotlin/space/blokk/Blokk.kt +++ b/blokk-api/src/main/kotlin/space/blokk/Blokk.kt @@ -9,6 +9,9 @@ import space.blokk.utils.UUIDAdapter import space.blokk.utils.UUIDWithoutHyphensAdapter interface BlokkProvider { + /** + * The [Server] instance. + */ val server: Server /** diff --git a/blokk-api/src/main/kotlin/space/blokk/net/protocols/play/JoinGamePacket.kt b/blokk-api/src/main/kotlin/space/blokk/net/protocols/play/JoinGamePacket.kt index 8eb8e87..cb155cc 100644 --- a/blokk-api/src/main/kotlin/space/blokk/net/protocols/play/JoinGamePacket.kt +++ b/blokk-api/src/main/kotlin/space/blokk/net/protocols/play/JoinGamePacket.kt @@ -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 diff --git a/blokk-api/src/main/kotlin/space/blokk/GameMode.kt b/blokk-api/src/main/kotlin/space/blokk/players/GameMode.kt similarity index 74% rename from blokk-api/src/main/kotlin/space/blokk/GameMode.kt rename to blokk-api/src/main/kotlin/space/blokk/players/GameMode.kt index a7da7e5..b48dcfd 100644 --- a/blokk-api/src/main/kotlin/space/blokk/GameMode.kt +++ b/blokk-api/src/main/kotlin/space/blokk/players/GameMode.kt @@ -1,4 +1,4 @@ -package space.blokk +package space.blokk.players enum class GameMode { SURVIVAL, diff --git a/blokk-api/src/main/kotlin/space/blokk/server/Server.kt b/blokk-api/src/main/kotlin/space/blokk/server/Server.kt index 1fcec9c..44ec8c1 100644 --- a/blokk-api/src/main/kotlin/space/blokk/server/Server.kt +++ b/blokk-api/src/main/kotlin/space/blokk/server/Server.kt @@ -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 { override val eventBus: EventBus val scope: CoroutineScope + + fun createTickChannel(): ReceiveChannel + + companion object { + const val TICKS_PER_SECOND = 20 + } } diff --git a/blokk-api/src/main/kotlin/space/blokk/utils/DelayTicks.kt b/blokk-api/src/main/kotlin/space/blokk/utils/DelayTicks.kt new file mode 100644 index 0000000..0992294 --- /dev/null +++ b/blokk-api/src/main/kotlin/space/blokk/utils/DelayTicks.kt @@ -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) diff --git a/blokk-api/src/main/kotlin/space/blokk/worlds/World.kt b/blokk-api/src/main/kotlin/space/blokk/worlds/World.kt new file mode 100644 index 0000000..2532b45 --- /dev/null +++ b/blokk-api/src/main/kotlin/space/blokk/worlds/World.kt @@ -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 +} diff --git a/blokk-server/build.gradle.kts b/blokk-server/build.gradle.kts index 324c1b5..ab0e915 100644 --- a/blokk-server/build.gradle.kts +++ b/blokk-server/build.gradle.kts @@ -48,6 +48,9 @@ dependencies { tasks { compileKotlin { kotlinOptions.jvmTarget = "1.8" + kotlinOptions.freeCompilerArgs = listOf( + "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" + ) } shadowJar { diff --git a/blokk-server/src/main/kotlin/space/blokk/BlokkServer.kt b/blokk-server/src/main/kotlin/space/blokk/BlokkServer.kt index c38cec6..d560f31 100644 --- a/blokk-server/src/main/kotlin/space/blokk/BlokkServer.kt +++ b/blokk-server/src/main/kotlin/space/blokk/BlokkServer.kt @@ -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() + 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 { diff --git a/blokk-server/src/main/kotlin/space/blokk/net/JoinProcedure.kt b/blokk-server/src/main/kotlin/space/blokk/net/JoinProcedure.kt index b6cece5..711b040 100644 --- a/blokk-server/src/main/kotlin/space/blokk/net/JoinProcedure.kt +++ b/blokk-server/src/main/kotlin/space/blokk/net/JoinProcedure.kt @@ -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 diff --git a/blokk-server/src/main/kotlin/space/blokk/utils/Ticker.kt b/blokk-server/src/main/kotlin/space/blokk/utils/Ticker.kt new file mode 100644 index 0000000..58fcea8 --- /dev/null +++ b/blokk-server/src/main/kotlin/space/blokk/utils/Ticker.kt @@ -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> = Collections.synchronizedSet(mutableSetOf>()) + + fun createTickChannel(): ReceiveChannel { + return Channel().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) + } + } + } +} diff --git a/build.gradle.kts b/build.gradle.kts index 571a7d1..d5e0eb8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,17 +9,3 @@ version = "0.0.1" repositories { mavenCentral() } - -dependencies { - -} - -tasks { - compileKotlin { - kotlinOptions.jvmTarget = "1.8" - } - - compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 87c7bae..8b3efc0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,7 +3,6 @@ pluginManagement { mavenCentral() gradlePluginPortal() } - } rootProject.name = "blokk"