From 468273eb6d7dfeb93bc77033f483c24140b39294 Mon Sep 17 00:00:00 2001 From: Moritz Ruth Date: Sun, 29 Nov 2020 17:51:21 +0100 Subject: [PATCH] Add SessionAfterLoginEvent --- .../src/main/kotlin/space/blokk/Difficulty.kt | 2 +- .../main/kotlin/space/blokk/net/Session.kt | 18 +- .../net/event/PlayerInitializationEvent.kt | 18 -- .../blokk/net/event/SessionAfterLoginEvent.kt | 85 ++++++++++ .../main/kotlin/space/blokk/player/Player.kt | 55 ++++++- .../main/kotlin/space/blokk/world/World.kt | 9 + .../net/packet/play/JoinGamePacketCodec.kt | 2 +- .../packet/play/PlayerAbilitiesPacketCodec.kt | 2 +- .../play/ServerDifficultyPacketCodec.kt | 4 +- .../blokk/net/packet/play/JoinGamePacket.kt | 7 +- .../net/packet/play/PlayerAbilitiesPacket.kt | 12 +- .../net/packet/play/ServerDifficultyPacket.kt | 4 +- .../space/blokk/net/LoginAndJoinProcedure.kt | 155 ++++++++++-------- .../kotlin/space/blokk/player/BlokkPlayer.kt | 8 +- .../main/kotlin/space/blokk/util/Hashing.kt | 5 + .../main/kotlin/space/blokk/util/Numbers.kt | 13 ++ build.gradle.kts | 1 + 17 files changed, 290 insertions(+), 110 deletions(-) create mode 100644 blokk-api/src/main/kotlin/space/blokk/net/event/SessionAfterLoginEvent.kt create mode 100644 blokk-server/src/main/kotlin/space/blokk/util/Hashing.kt create mode 100644 blokk-server/src/main/kotlin/space/blokk/util/Numbers.kt diff --git a/blokk-api/src/main/kotlin/space/blokk/Difficulty.kt b/blokk-api/src/main/kotlin/space/blokk/Difficulty.kt index ce9c54d..d0bc7a4 100644 --- a/blokk-api/src/main/kotlin/space/blokk/Difficulty.kt +++ b/blokk-api/src/main/kotlin/space/blokk/Difficulty.kt @@ -7,4 +7,4 @@ enum class Difficulty { HARD } -data class DifficultyOptions(val difficulty: Difficulty, val locked: Boolean) +data class DifficultySettings(val difficulty: Difficulty, val locked: Boolean) diff --git a/blokk-api/src/main/kotlin/space/blokk/net/Session.kt b/blokk-api/src/main/kotlin/space/blokk/net/Session.kt index 80c332d..753a363 100644 --- a/blokk-api/src/main/kotlin/space/blokk/net/Session.kt +++ b/blokk-api/src/main/kotlin/space/blokk/net/Session.kt @@ -7,7 +7,9 @@ import space.blokk.event.EventTarget import space.blokk.net.event.SessionEvent import space.blokk.net.packet.OutgoingPacket import space.blokk.net.packet.Protocol +import space.blokk.player.GameMode import space.blokk.player.Player +import space.blokk.world.WorldAndLocationWithRotation import java.net.InetAddress import java.util.* @@ -46,7 +48,7 @@ interface Session : EventTarget { /** * The current state of this session. */ - var state: State + val state: State sealed class State { // TODO: Add documentation for the different states @@ -61,7 +63,19 @@ interface Session : EventTarget { class LoginSucceeded(val username: String, val uuid: UUID) : State() - class WaitingForClientSettings(val username: String, val uuid: UUID) : State() + class WaitingForClientSettings( + val username: String, + val uuid: UUID, + val flying: Boolean, + val canFly: Boolean, + val flyingSpeed: Float, + val fieldOfView: Float, + val gameMode: GameMode, + val initialWorldAndLocation: WorldAndLocationWithRotation, + val invulnerable: Boolean, + val reducedDebugInfo: Boolean, + val selectedHotbarSlot: Byte + ) : State() interface WithPlayer { val player: Player diff --git a/blokk-api/src/main/kotlin/space/blokk/net/event/PlayerInitializationEvent.kt b/blokk-api/src/main/kotlin/space/blokk/net/event/PlayerInitializationEvent.kt index 699c07d..be9fabc 100644 --- a/blokk-api/src/main/kotlin/space/blokk/net/event/PlayerInitializationEvent.kt +++ b/blokk-api/src/main/kotlin/space/blokk/net/event/PlayerInitializationEvent.kt @@ -2,9 +2,7 @@ package space.blokk.net.event import space.blokk.event.Cancellable import space.blokk.net.Session -import space.blokk.player.GameMode import space.blokk.player.Player -import space.blokk.world.WorldAndLocationWithRotation /** * Emitted when a [Player] instance will be initialized. @@ -13,20 +11,4 @@ import space.blokk.world.WorldAndLocationWithRotation */ class PlayerInitializationEvent(session: Session, val settings: Player.Settings) : SessionEvent(session), Cancellable { override var cancelled = false - - /** - * The location where the player will spawn. If this is null after all handlers ran, the player will disconnect. - */ - var initialWorldAndLocation: WorldAndLocationWithRotation? = null - - var gameMode: GameMode = GameMode.SURVIVAL - - /** - * See [Player.selectedHotbarSlot]. - */ - var selectedHotbarSlot: Byte = 0 - set(value) { - if (value in 0..8) field = value - else throw IllegalArgumentException("selectedHotbarSlot must be between 0 and 8") - } } diff --git a/blokk-api/src/main/kotlin/space/blokk/net/event/SessionAfterLoginEvent.kt b/blokk-api/src/main/kotlin/space/blokk/net/event/SessionAfterLoginEvent.kt new file mode 100644 index 0000000..5ad6b0d --- /dev/null +++ b/blokk-api/src/main/kotlin/space/blokk/net/event/SessionAfterLoginEvent.kt @@ -0,0 +1,85 @@ +package space.blokk.net.event + +import space.blokk.event.Cancellable +import space.blokk.net.Session +import space.blokk.player.GameMode +import space.blokk.player.Player +import space.blokk.world.WorldAndLocationWithRotation + +/** + * Emitted after a [Session] finished logging in. + * + * If the event is cancelled, the session is disconnected. + */ +class SessionAfterLoginEvent(session: Session) : SessionEvent(session), Cancellable { + override var cancelled = false + + /** + * Whether the respawn screen is shown when the player dies. + */ + var respawnScreenEnabled: Boolean = true + + /** + * The location where the player will spawn. If this is null after all handlers ran, the session is disconnected. + */ + var initialWorldAndLocation: WorldAndLocationWithRotation? = null + + var maxViewDistance: Int = 32 + set(value) { + if (value in 2..32) field = value + else throw IllegalArgumentException("maxViewDistance must be in 2..32") + } + + /** + * Whether the player should see his hearts as they look in hardcore mode. + */ + var hardcoreHearts = false + + /** + * See [Player.gameMode]. + */ + var gameMode: GameMode = GameMode.SURVIVAL + + /** + * See [Player.selectedHotbarSlot]. + */ + var selectedHotbarSlot: Byte = 0 + set(value) { + if (value in 0..8) field = value + else throw IllegalArgumentException("selectedHotbarSlot must be in 0..8") + } + + /** + * See [Player.reducedDebugInfo]. + */ + var reducedDebugInfo: Boolean = false + + /** + * See [Player.invulnerable]. + */ + var invulnerable: Boolean = false + + /** + * See [Player.canFly]. + */ + var canFly: Boolean = false + + /** + * See [Player.flying]. + */ + var flying: Boolean = false + + /** + * See [Player.flyingSpeed]. + * + * Defaults to [Player.DEFAULT_FLYING_SPEED]. + */ + var flyingSpeed: Float = Player.DEFAULT_FLYING_SPEED + + /** + * See [Player.fieldOfView]. + * + * Defaults to [Player.DEFAULT_FIELD_OF_VIEW]. + */ + var fieldOfView: Float = Player.DEFAULT_FIELD_OF_VIEW +} diff --git a/blokk-api/src/main/kotlin/space/blokk/player/Player.kt b/blokk-api/src/main/kotlin/space/blokk/player/Player.kt index 027875e..6767b6c 100644 --- a/blokk-api/src/main/kotlin/space/blokk/player/Player.kt +++ b/blokk-api/src/main/kotlin/space/blokk/player/Player.kt @@ -42,6 +42,15 @@ interface Player : EventTarget { */ val settings: Settings + data class Settings( + val viewDistance: Byte, + val locale: String, + val mainHand: Hand, + val enabledSkinParts: SkinPartsConfiguration, + val chatColorsEnabled: Boolean, + val chatMode: ChatMode + ) + /** * The current location of this player. */ @@ -58,12 +67,42 @@ interface Player : EventTarget { */ var selectedHotbarSlot: Byte - data class Settings( - val viewDistance: Byte, - val locale: String, - val mainHand: Hand, - val enabledSkinParts: SkinPartsConfiguration, - val chatColorsEnabled: Boolean, - val chatMode: ChatMode - ) + /** + * Corresponds to the `reducedDebugInfo` gamerule in vanilla. + * + * @see https://minecraft.gamepedia.com/Debug_screen#Legend + */ + var reducedDebugInfo: Boolean + + /** + * Whether the player cannot take damage. + */ + var invulnerable: Boolean + + /** + * Whether the player can start flying by itself. + */ + var canFly: Boolean + + /** + * Whether the player is currently flying. + */ + var flying: Boolean + + /** + * The default is [DEFAULT_FLYING_SPEED]. + */ + var flyingSpeed: Float + + /** + * Modifies the field of view, like a speed potion. + * + * The default is [DEFAULT_FIELD_OF_VIEW]. + */ + var fieldOfView: Float + + companion object { + const val DEFAULT_FIELD_OF_VIEW = 0.1f + const val DEFAULT_FLYING_SPEED = 0.05f + } } diff --git a/blokk-api/src/main/kotlin/space/blokk/world/World.kt b/blokk-api/src/main/kotlin/space/blokk/world/World.kt index f60193b..829b58c 100644 --- a/blokk-api/src/main/kotlin/space/blokk/world/World.kt +++ b/blokk-api/src/main/kotlin/space/blokk/world/World.kt @@ -22,6 +22,15 @@ abstract class World(val uuid: UUID) { abstract val loadedChunks: Map abstract val type: WorldType + /** + * This can be any value. + * + * Only the first 8 bytes of the SHA-256 hash of this value are sent to the client + * (and he seems not to use it in any way). + * A random value will be used if this is null. + */ + open val seed: Long? = null + /** * All entities in this world. Use [spawnEntity] for spawning new ones. */ diff --git a/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/JoinGamePacketCodec.kt b/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/JoinGamePacketCodec.kt index 7f6a46c..ee3cacd 100644 --- a/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/JoinGamePacketCodec.kt +++ b/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/JoinGamePacketCodec.kt @@ -25,7 +25,7 @@ object JoinGamePacketCodec : OutgoingPacketCodec(0x26, JoinGameP } ) - dst.writeVarInt(viewDistance.toInt()) + dst.writeVarInt(maxViewDistance) dst.writeBoolean(reducedDebugInfo) dst.writeBoolean(respawnScreenEnabled) } diff --git a/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/PlayerAbilitiesPacketCodec.kt b/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/PlayerAbilitiesPacketCodec.kt index 801430e..ce6a2c7 100644 --- a/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/PlayerAbilitiesPacketCodec.kt +++ b/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/PlayerAbilitiesPacketCodec.kt @@ -8,7 +8,7 @@ object PlayerAbilitiesPacketCodec : OutgoingPacketCodec(0 var flags = 0 if (invulnerable) flags = flags and 0x01 if (flying) flags = flags and 0x02 - if (flyingAllowed) flags = flags and 0x04 + if (canFly) flags = flags and 0x04 if (instantlyBreakBlocks) flags = flags and 0x08 dst.writeByte(flags) diff --git a/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/ServerDifficultyPacketCodec.kt b/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/ServerDifficultyPacketCodec.kt index 0ae20c9..2a031de 100644 --- a/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/ServerDifficultyPacketCodec.kt +++ b/blokk-packet-codecs/src/main/kotlin/space/blokk/net/packet/play/ServerDifficultyPacketCodec.kt @@ -7,7 +7,7 @@ import space.blokk.net.packet.OutgoingPacketCodec object ServerDifficultyPacketCodec : OutgoingPacketCodec(0x0E, ServerDifficultyPacket::class) { override fun ServerDifficultyPacket.encode(dst: ByteBuf) { dst.writeByte( - when (difficultyOptions.difficulty) { + when (difficultySettings.difficulty) { Difficulty.PEACEFUL -> 0 Difficulty.EASY -> 1 Difficulty.NORMAL -> 2 @@ -15,6 +15,6 @@ object ServerDifficultyPacketCodec : OutgoingPacketCodec } ) - dst.writeBoolean(difficultyOptions.locked) + dst.writeBoolean(difficultySettings.locked) } } diff --git a/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/JoinGamePacket.kt b/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/JoinGamePacket.kt index c45eb8e..8420dab 100644 --- a/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/JoinGamePacket.kt +++ b/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/JoinGamePacket.kt @@ -10,11 +10,10 @@ import space.blokk.world.WorldType * * @param entityID ID of the player entity. * @param gameMode Game mode of the player. - * @param hardcore Whether the player is in hardcore mode. * @param worldDimension Dimension of the world the player joins. * @param worldSeedHash First 8 bytes of the SHA-256 hash of the world's seed. * @param worldType Type of the world the player joins. - * @param viewDistance Maximum view distance. + * @param maxViewDistance Maximum view distance allowed by the server. * @param reducedDebugInfo Whether the debug screen shows only reduced info. * @param respawnScreenEnabled Whether the respawn screen is shown when the player dies. */ @@ -25,11 +24,11 @@ data class JoinGamePacket( val worldDimension: WorldDimension, val worldSeedHash: Long, val worldType: WorldType, - val viewDistance: Byte, + val maxViewDistance: Int, val reducedDebugInfo: Boolean, val respawnScreenEnabled: Boolean ) : OutgoingPacket() { init { - if (viewDistance < 2 || viewDistance > 32) throw IllegalArgumentException("viewDistance must be between 2 and 32.") + if (maxViewDistance !in 2..32) throw IllegalArgumentException("viewDistance must be in 2..32") } } diff --git a/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/PlayerAbilitiesPacket.kt b/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/PlayerAbilitiesPacket.kt index 8fcd6eb..a12346e 100644 --- a/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/PlayerAbilitiesPacket.kt +++ b/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/PlayerAbilitiesPacket.kt @@ -7,16 +7,16 @@ import space.blokk.net.packet.OutgoingPacket * * @param invulnerable Whether the player is invulnerable. * @param flying Whether the player is currently flying. - * @param flyingAllowed Whether the player is allowed to fly. + * @param canFly Whether the player is allowed to fly. * @param instantlyBreakBlocks Whether can break blocks instantly like in creative mode. - * @param flyingSpeed The player's flying speed. The default value is `0.5` - * @param fieldOfView The player's field of view modifier. The default value is `0.1`. + * @param flyingSpeed The player's flying speed. + * @param fieldOfView The player's field of view modifier. */ data class PlayerAbilitiesPacket( val invulnerable: Boolean, val flying: Boolean, - val flyingAllowed: Boolean, + val canFly: Boolean, val instantlyBreakBlocks: Boolean, - val flyingSpeed: Float = 0.5f, - val fieldOfView: Float = 0.1f + val flyingSpeed: Float, + val fieldOfView: Float ) : OutgoingPacket() diff --git a/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/ServerDifficultyPacket.kt b/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/ServerDifficultyPacket.kt index 0d6bd03..29ab149 100644 --- a/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/ServerDifficultyPacket.kt +++ b/blokk-packets/src/main/kotlin/space/blokk/net/packet/play/ServerDifficultyPacket.kt @@ -1,9 +1,9 @@ package space.blokk.net.packet.play -import space.blokk.DifficultyOptions +import space.blokk.DifficultySettings import space.blokk.net.packet.OutgoingPacket /** * Sets the difficulty shown in the pause menu. */ -data class ServerDifficultyPacket(val difficultyOptions: DifficultyOptions) : OutgoingPacket() +data class ServerDifficultyPacket(val difficultySettings: DifficultySettings) : OutgoingPacket() diff --git a/blokk-server/src/main/kotlin/space/blokk/net/LoginAndJoinProcedure.kt b/blokk-server/src/main/kotlin/space/blokk/net/LoginAndJoinProcedure.kt index 51ce79a..4982535 100644 --- a/blokk-server/src/main/kotlin/space/blokk/net/LoginAndJoinProcedure.kt +++ b/blokk-server/src/main/kotlin/space/blokk/net/LoginAndJoinProcedure.kt @@ -3,10 +3,12 @@ package space.blokk.net import io.netty.buffer.Unpooled import space.blokk.BlokkServer import space.blokk.Difficulty -import space.blokk.DifficultyOptions +import space.blokk.DifficultySettings import space.blokk.chat.TextComponent +import space.blokk.event.ifCancelled import space.blokk.net.MinecraftProtocolDataTypes.writeString import space.blokk.net.event.PlayerInitializationEvent +import space.blokk.net.event.SessionAfterLoginEvent import space.blokk.net.packet.login.EncryptionRequestPacket import space.blokk.net.packet.login.EncryptionResponsePacket import space.blokk.net.packet.login.LoginStartPacket @@ -14,15 +16,13 @@ import space.blokk.net.packet.login.LoginSuccessPacket import space.blokk.net.packet.play.* import space.blokk.player.BlokkPlayer import space.blokk.player.GameMode -import space.blokk.util.AuthenticationHelper -import space.blokk.util.EncryptionUtils +import space.blokk.util.* import space.blokk.world.Chunk -import space.blokk.world.WorldDimension -import space.blokk.world.WorldType import java.security.MessageDigest import java.util.* import javax.crypto.Cipher import javax.crypto.spec.SecretKeySpec +import kotlin.random.Random class LoginAndJoinProcedure(val session: BlokkSession) { suspend fun start(packet: LoginStartPacket) { @@ -77,48 +77,7 @@ class LoginAndJoinProcedure(val session: BlokkSession) { private suspend fun afterLogin() { val state: Session.State.LoginSucceeded = session.state.getOrFail() - // TODO: Use real data - session.send( - JoinGamePacket( - 0, - GameMode.CREATIVE, - false, - WorldDimension.OVERWORLD, - 12, - WorldType.DEFAULT, - 32, - reducedDebugInfo = false, - respawnScreenEnabled = true - ) - ) - - session.sendPluginMessage( - "minecraft:brand", - Unpooled.buffer().writeString("Blokk ${BlokkServer.VERSION_WITH_V}") - ) - - // TODO: Use real data - session.send(ServerDifficultyPacket(DifficultyOptions(Difficulty.NORMAL, false))) - - // TODO: Use real data - session.send( - PlayerAbilitiesPacket( - invulnerable = false, - flying = false, - flyingAllowed = true, - instantlyBreakBlocks = true, - flyingSpeed = 0.2f, - fieldOfView = 0.2f - ) - ) - - session.state = Session.State.WaitingForClientSettings(state.username, state.uuid) - } - - suspend fun onClientSettingsReceived(packet: ClientSettingsPacket) { - val state = session.state.getOrFail() - - val event = session.emit(PlayerInitializationEvent(session, packet.asPlayerSettings())) + val event = session.emit(SessionAfterLoginEvent(session)) val initialWorldAndLocation = event.initialWorldAndLocation when { @@ -128,31 +87,99 @@ class LoginAndJoinProcedure(val session: BlokkSession) { session.disconnect(loggableReason = "No spawn location set") } else -> { - session.state = Session.State.JoiningWorld( - BlokkPlayer( - session, - state.username, - state.uuid, + val seedAsBytes = (initialWorldAndLocation.world.seed ?: Random.nextLong()).toByteArray() + + // TODO: Spawn the player entity + session.send( + JoinGamePacket( + 0, event.gameMode, - event.settings, - initialWorldAndLocation.world, - initialWorldAndLocation.location, - event.selectedHotbarSlot + event.hardcoreHearts, + initialWorldAndLocation.world.dimension, + sha256(seedAsBytes).toLong(), + initialWorldAndLocation.world.type, + event.maxViewDistance, + event.reducedDebugInfo, + event.respawnScreenEnabled ) ) - session.send(SetSelectedHotbarSlotPacket(event.selectedHotbarSlot)) + session.sendPluginMessage( + "minecraft:brand", + Unpooled.buffer().writeString("Blokk ${BlokkServer.VERSION_WITH_V}") + ) - // TODO: Send Declare Recipes packet - // TODO: Send Tags packet - // TODO: Send Entity Status packet with OP permission level + // As this is only visual, there is no way of changing this aside from intercepting the packet. + session.send(ServerDifficultyPacket(DifficultySettings(Difficulty.NORMAL, false))) - session.send(PlayerPositionAndLookPacket(initialWorldAndLocation.location)) + session.send( + PlayerAbilitiesPacket( + event.invulnerable, + event.flying, + event.canFly, + // TODO: Consider allowing to modify this value + event.gameMode == GameMode.CREATIVE, + // TODO: Find out how this relates to the entity property named `generic.flying_speed` + event.flyingSpeed, + event.fieldOfView + ) + ) - // TODO: Send PlayerInfo packet - - session.send(UpdateViewPositionPacket(Chunk.Key.from(session.player!!.location.asVoxelLocation()))) + session.state = Session.State.WaitingForClientSettings( + state.username, + state.uuid, + event.flying, + event.canFly, + event.flyingSpeed, + event.fieldOfView, + event.gameMode, + initialWorldAndLocation, + event.invulnerable, + event.reducedDebugInfo, + event.selectedHotbarSlot + ) } } } + + suspend fun onClientSettingsReceived(packet: ClientSettingsPacket) { + val state: Session.State.WaitingForClientSettings = session.state.getOrFail() + val settings = packet.asPlayerSettings() + + session.emit(PlayerInitializationEvent(session, settings)).ifCancelled { + session.disconnect(loggableReason = "PlayerInitializationEvent was cancelled") + return + } + + session.state = Session.State.JoiningWorld( + BlokkPlayer( + session, + state.username, + state.uuid, + state.gameMode, + settings, + state.initialWorldAndLocation.world, + state.initialWorldAndLocation.location, + state.reducedDebugInfo, + state.fieldOfView, + state.canFly, + state.flying, + state.flyingSpeed, + state.invulnerable, + state.selectedHotbarSlot + ) + ) + + session.send(SetSelectedHotbarSlotPacket(state.selectedHotbarSlot)) + + // TODO: Send Declare Recipes packet + // TODO: Send Tags packet + // TODO: Send Entity Status packet with OP permission level + + session.send(PlayerPositionAndLookPacket(state.initialWorldAndLocation.location)) + + // TODO: Send PlayerInfo packet + + session.send(UpdateViewPositionPacket(Chunk.Key.from(session.player!!.location.asVoxelLocation()))) + } } diff --git a/blokk-server/src/main/kotlin/space/blokk/player/BlokkPlayer.kt b/blokk-server/src/main/kotlin/space/blokk/player/BlokkPlayer.kt index 9ec0672..8b05af7 100644 --- a/blokk-server/src/main/kotlin/space/blokk/player/BlokkPlayer.kt +++ b/blokk-server/src/main/kotlin/space/blokk/player/BlokkPlayer.kt @@ -18,6 +18,12 @@ class BlokkPlayer( override var settings: Player.Settings, override val world: World, override var location: LocationWithRotation, + override var reducedDebugInfo: Boolean, + override var fieldOfView: Float, + override var canFly: Boolean, + override var flying: Boolean, + override var flyingSpeed: Float, + override var invulnerable: Boolean, selectedHotbarSlot: Byte ) : Player { private val identifier = "BlokkPlayer($username)" @@ -30,7 +36,7 @@ class BlokkPlayer( override var selectedHotbarSlot: Byte = 0 set(value) { if (value in 0..8) field = value - else throw IllegalArgumentException("selectedHotbarSlot must be between 0 and 8") + else throw IllegalArgumentException("selectedHotbarSlot must be in 0..8") } init { diff --git a/blokk-server/src/main/kotlin/space/blokk/util/Hashing.kt b/blokk-server/src/main/kotlin/space/blokk/util/Hashing.kt new file mode 100644 index 0000000..91099d2 --- /dev/null +++ b/blokk-server/src/main/kotlin/space/blokk/util/Hashing.kt @@ -0,0 +1,5 @@ +package space.blokk.util + +import java.security.MessageDigest + +fun sha256(bytes: ByteArray): ByteArray = MessageDigest.getInstance("SHA-256").run { digest(bytes) } diff --git a/blokk-server/src/main/kotlin/space/blokk/util/Numbers.kt b/blokk-server/src/main/kotlin/space/blokk/util/Numbers.kt new file mode 100644 index 0000000..9769cf5 --- /dev/null +++ b/blokk-server/src/main/kotlin/space/blokk/util/Numbers.kt @@ -0,0 +1,13 @@ +package space.blokk.util + +import java.nio.ByteBuffer + +@Suppress("UsePropertyAccessSyntax") +fun ByteArray.toLong() = ByteBuffer.allocate(Long.SIZE_BYTES).also { + it.put(this) + it.flip() +}.getLong() + +fun Long.toByteArray() = ByteBuffer.allocate(Long.SIZE_BYTES).also { + it.putLong(this) +}.array() diff --git a/build.gradle.kts b/build.gradle.kts index 925813c..bad8531 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,5 @@ plugins { + // TODO: Update to 1.4.2 kotlin("jvm") version "1.4.0" kotlin("kapt") version "1.4.0" id("minecraft-data-sources")