From fd233b9ab53de3d07c0450633e825ef22a2ac367 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 12 Feb 2024 16:06:51 +0700 Subject: [PATCH] More work on legacy protocol --- gradle.properties | 2 +- .../kotlin/ru/dbotthepony/kstarbound/Main.kt | 3 +- .../kstarbound/client/ClientConnection.kt | 2 + .../network/packets/ChunkCellsPacket.kt | 4 +- .../network/packets/ForgetChunkPacket.kt | 4 +- .../dbotthepony/kstarbound/defs/Celestial.kt | 6 +- .../kstarbound/defs/player/ShipUpgrades.kt | 22 +-- .../ru/dbotthepony/kstarbound/io/Streams.kt | 18 -- .../kstarbound/json/BinaryJsonReader.kt | 3 +- .../kstarbound/network/Connection.kt | 4 +- .../kstarbound/network/PacketRegistry.kt | 156 ++++++++++-------- .../network/packets/ProtocolResponsePacket.kt | 4 +- .../clientbound/ConnectSuccessPacket.kt | 8 +- .../packets/clientbound/WorldStartPacket.kt | 77 +++++++++ .../serverbound/ClientConnectPacket.kt | 2 +- .../network/packets/TrackedPositionPacket.kt | 8 +- .../kstarbound/world/WorldGeometry.kt | 8 +- 17 files changed, 209 insertions(+), 122 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/clientbound/WorldStartPacket.kt diff --git a/gradle.properties b/gradle.properties index 82366e11..40ece3d5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ kotlin.code.style=official org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m kotlinVersion=1.9.0 -kommonsVersion=2.1.5 +kommonsVersion=2.1.8 ffiVersion=2.2.13 lwjglVersion=3.3.0 diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt index 633247b8..4b03bfe1 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt @@ -83,7 +83,8 @@ fun main() { //item.movement.applyVelocity(Vector2d(rand.nextDouble() * 1000.0 - 500.0, rand.nextDouble() * 1000.0 - 500.0)) } - client.connectToLocalServer(server.channels.createLocalChannel(), UUID.randomUUID()) + //client.connectToLocalServer(server.channels.createLocalChannel(), UUID.randomUUID()) + client.connectToRemoteServer(InetSocketAddress("127.0.0.1", 21025), UUID.randomUUID()) //client2.connectToLocalServer(server.channels.createLocalChannel(), UUID.randomUUID()) server.channels.createChannel(InetSocketAddress(21060)) } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientConnection.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientConnection.kt index 545d01f3..d1dd17a0 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientConnection.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientConnection.kt @@ -24,6 +24,8 @@ class ClientConnection(val client: StarboundClient, type: ConnectionType, uuid: sendAndFlush(ProtocolRequestPacket(Starbound.LEGACY_PROTOCOL_VERSION)) } + var connectionID: Int = -1 + override fun inGame() { } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/network/packets/ChunkCellsPacket.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/network/packets/ChunkCellsPacket.kt index 51805abc..43f5c84b 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/network/packets/ChunkCellsPacket.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/network/packets/ChunkCellsPacket.kt @@ -2,10 +2,10 @@ package ru.dbotthepony.kstarbound.client.network.packets import ru.dbotthepony.kommons.io.readCollection import ru.dbotthepony.kommons.io.writeCollection +import ru.dbotthepony.kommons.io.writeStruct2i import ru.dbotthepony.kstarbound.client.ClientConnection import ru.dbotthepony.kstarbound.network.IClientPacket import ru.dbotthepony.kstarbound.io.readChunkPos -import ru.dbotthepony.kstarbound.io.writeVec2i import ru.dbotthepony.kstarbound.world.CHUNK_SIZE import ru.dbotthepony.kstarbound.world.Chunk import ru.dbotthepony.kstarbound.world.ChunkPos @@ -25,7 +25,7 @@ class ChunkCellsPacket(val pos: ChunkPos, val data: List) : IClie }) override fun write(stream: DataOutputStream, isLegacy: Boolean) { - stream.writeVec2i(pos) + stream.writeStruct2i(pos) stream.writeCollection(data) { it.write(stream) } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/network/packets/ForgetChunkPacket.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/network/packets/ForgetChunkPacket.kt index 05ae5a50..90a75e5f 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/network/packets/ForgetChunkPacket.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/network/packets/ForgetChunkPacket.kt @@ -1,9 +1,9 @@ package ru.dbotthepony.kstarbound.client.network.packets +import ru.dbotthepony.kommons.io.writeStruct2i import ru.dbotthepony.kstarbound.client.ClientConnection import ru.dbotthepony.kstarbound.network.IClientPacket import ru.dbotthepony.kstarbound.io.readChunkPos -import ru.dbotthepony.kstarbound.io.writeVec2i import ru.dbotthepony.kstarbound.world.ChunkPos import java.io.DataInputStream import java.io.DataOutputStream @@ -12,7 +12,7 @@ class ForgetChunkPacket(val pos: ChunkPos) : IClientPacket { constructor(stream: DataInputStream, isLegacy: Boolean) : this(stream.readChunkPos()) override fun write(stream: DataOutputStream, isLegacy: Boolean) { - stream.writeVec2i(pos) + stream.writeStruct2i(pos) } override fun play(connection: ClientConnection) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/Celestial.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/Celestial.kt index 06e7e8e1..6ea60274 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/Celestial.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/Celestial.kt @@ -1,8 +1,8 @@ package ru.dbotthepony.kstarbound.defs +import ru.dbotthepony.kommons.io.readVector2i import ru.dbotthepony.kommons.io.writeStruct2i import ru.dbotthepony.kommons.vector.Vector2i -import ru.dbotthepony.kstarbound.io.readVec2i import ru.dbotthepony.kstarbound.json.builder.JsonFactory import java.io.DataInputStream import java.io.DataOutputStream @@ -19,8 +19,8 @@ data class CelestialBaseInformation( stream.readInt(), stream.readInt(), stream.readInt(), - stream.readVec2i(), - stream.readVec2i(), + stream.readVector2i(), + stream.readVector2i(), ) fun write(stream: DataOutputStream, isLegacy: Boolean) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/player/ShipUpgrades.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/player/ShipUpgrades.kt index 47bcfc51..f2741c4a 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/player/ShipUpgrades.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/player/ShipUpgrades.kt @@ -19,6 +19,15 @@ data class ShipUpgrades( val shipSpeed: Int = 0, val capabilities: ImmutableSet = ImmutableSet.of() ) { + constructor(stream: DataInputStream, isLegacy: Boolean) : this( + stream.readInt(), + stream.readInt(), + stream.readInt(), + if (isLegacy) stream.readFloat().toDouble() else stream.readDouble(), + stream.readInt(), + ImmutableSet.copyOf(stream.readCollection { readBinaryString() }) + ) + fun apply(upgrades: ShipUpgrades): ShipUpgrades { return ShipUpgrades( shipLevel = shipLevel.coerceAtLeast(upgrades.shipLevel), @@ -43,17 +52,4 @@ data class ShipUpgrades( stream.writeInt(shipSpeed) stream.writeCollection(capabilities) { writeBinaryString(it) } } - - companion object { - fun read(stream: DataInputStream, isLegacy: Boolean): ShipUpgrades { - return ShipUpgrades( - stream.readInt(), - stream.readInt(), - stream.readInt(), - if (isLegacy) stream.readFloat().toDouble() else stream.readDouble(), - stream.readInt(), - ImmutableSet.copyOf(stream.readCollection { readBinaryString() }) - ) - } - } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/Streams.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/Streams.kt index 073601eb..3cc37131 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/io/Streams.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/Streams.kt @@ -37,24 +37,6 @@ fun InputStream.readHeader(header: String) { } } -fun OutputStream.writeVec2i(value: IStruct2i) { - writeSignedVarInt(value.component1()) - writeSignedVarInt(value.component2()) -} - -fun OutputStream.writeVec2d(value: IStruct2d) { - writeDouble(value.component1()) - writeDouble(value.component2()) -} - -fun InputStream.readVec2i(): Vector2i { - return Vector2i(readSignedVarInt(), readSignedVarInt()) -} - -fun InputStream.readVec2d(): Vector2d { - return Vector2d(readDouble(), readDouble()) -} - fun InputStream.readChunkPos(): ChunkPos { return ChunkPos(readSignedVarInt(), readSignedVarInt()) } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/json/BinaryJsonReader.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/json/BinaryJsonReader.kt index 116b9f91..95941354 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/json/BinaryJsonReader.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/json/BinaryJsonReader.kt @@ -24,7 +24,7 @@ import java.util.LinkedList */ fun DataInputStream.readJsonElement(): JsonElement { return when (val id = read()) { - BinaryJsonReader.TYPE_NULL -> JsonNull.INSTANCE + BinaryJsonReader.TYPE_INVALID, BinaryJsonReader.TYPE_NULL -> JsonNull.INSTANCE BinaryJsonReader.TYPE_DOUBLE -> JsonPrimitive(readDouble()) BinaryJsonReader.TYPE_BOOLEAN -> InternedJsonElementAdapter.of(readBoolean()) BinaryJsonReader.TYPE_INT -> JsonPrimitive(readSignedVarLong()) @@ -388,6 +388,7 @@ class BinaryJsonReader(private val stream: DataInputStream) : JsonReader(unreada } companion object { + const val TYPE_INVALID = 0x00 const val TYPE_NULL = 0x01 const val TYPE_DOUBLE = 0x02 const val TYPE_BOOLEAN = 0x03 diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/network/Connection.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/network/Connection.kt index df49c653..f7bcd292 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/network/Connection.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/network/Connection.kt @@ -35,7 +35,7 @@ abstract class Connection(val side: ConnectionSide, val type: ConnectionType, va private val legacySerializer = PacketRegistry.LEGACY.Serializer(side) fun setupLegacy() { - LOGGER.info("Handshake successful from ${channel.remoteAddress()}, channel is using legacy protocol") + LOGGER.info("Handshake successful on ${channel.remoteAddress()}, channel is using legacy protocol") if (type == ConnectionType.MEMORY) { channel.pipeline().remove(handshakeValidator) @@ -49,7 +49,7 @@ abstract class Connection(val side: ConnectionSide, val type: ConnectionType, va } fun setupNative() { - LOGGER.info("Handshake successful from ${channel.remoteAddress()}, channel is using native protocol") + LOGGER.info("Handshake successful on ${channel.remoteAddress()}, channel is using native protocol") if (type == ConnectionType.MEMORY) { channel.pipeline().remove(handshakeValidator) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/network/PacketRegistry.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/network/PacketRegistry.kt index 7f5122c3..371102ee 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/network/PacketRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/network/PacketRegistry.kt @@ -7,12 +7,15 @@ import io.netty.channel.ChannelDuplexHandler import io.netty.channel.ChannelHandlerContext import io.netty.channel.ChannelPromise import it.unimi.dsi.fastutil.bytes.ByteArrayList +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap import it.unimi.dsi.fastutil.io.FastByteArrayInputStream import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import org.apache.logging.log4j.LogManager import ru.dbotthepony.kommons.io.readSignedVarInt +import ru.dbotthepony.kommons.io.readVarInt import ru.dbotthepony.kommons.io.writeSignedVarInt +import ru.dbotthepony.kommons.io.writeVarInt import ru.dbotthepony.kstarbound.client.network.packets.ForgetChunkPacket import ru.dbotthepony.kstarbound.client.network.packets.ChunkCellsPacket import ru.dbotthepony.kstarbound.client.network.packets.ForgetEntityPacket @@ -25,6 +28,7 @@ import ru.dbotthepony.kstarbound.network.packets.serverbound.HandshakeResponsePa import ru.dbotthepony.kstarbound.network.packets.ProtocolRequestPacket import ru.dbotthepony.kstarbound.network.packets.ProtocolResponsePacket import ru.dbotthepony.kstarbound.network.packets.clientbound.ServerDisconnectPacket +import ru.dbotthepony.kstarbound.network.packets.clientbound.WorldStartPacket import ru.dbotthepony.kstarbound.server.network.packets.TrackedPositionPacket import ru.dbotthepony.kstarbound.server.network.packets.TrackedSizePacket import java.io.BufferedInputStream @@ -37,6 +41,7 @@ import kotlin.reflect.KClass class PacketRegistry(val isLegacy: Boolean) { private val packets = ArrayList?>() + private val missingNames = Int2ObjectArrayMap() private val clazz2Type = Reference2ObjectOpenHashMap, Type<*>>() private data class Type(val id: Int, val type: KClass, val factory: IPacketReader, val direction: PacketDirection) @@ -67,6 +72,11 @@ class PacketRegistry(val isLegacy: Boolean) { } } + private fun skip(name: String) { + missingNames[packets.size] = name + packets.add(null) + } + inner class Serializer(val side: ConnectionSide) : ChannelDuplexHandler() { private val backlog = ByteArrayList() private var discardBytes = 0 @@ -121,12 +131,19 @@ class PacketRegistry(val isLegacy: Boolean) { val type = packets.getOrNull(packetType) if (type == null) { - LOGGER.error("Unknown packet type $packetType! Discarding ${dataLength.absoluteValue} bytes") + val name = missingNames[packetType] + + if (name != null) + LOGGER.error("Unknown packet type $packetType ($name)! Discarding ${dataLength.absoluteValue} bytes") + else + LOGGER.error("Unknown packet type $packetType! Discarding ${dataLength.absoluteValue} bytes") + discardBytes = dataLength.absoluteValue } else if (!type.direction.acceptedOn(side)) { LOGGER.error("Packet type $packetType (${type.type}) can not be accepted on side $side! Discarding ${dataLength.absoluteValue} bytes") discardBytes = dataLength.absoluteValue } else { + LOGGER.debug("Packet type {} ({}) received on {} (size {} bytes)", packetType, type.type, side, dataLength.absoluteValue) readingType = type readableBytes = dataLength.absoluteValue isCompressed = dataLength < 0 @@ -159,6 +176,7 @@ class PacketRegistry(val isLegacy: Boolean) { stream2.writeByte(type.id) stream2.writeSignedVarInt(stream.length) stream2.write(stream.array, 0, stream.length) + LOGGER.debug("Packet type {} ({}) sent from {} (size {} bytes)", type.id, type.type, side, stream.length) ctx.write(buff, promise) } } @@ -213,92 +231,100 @@ class PacketRegistry(val isLegacy: Boolean) { HANDSHAKE.add(::ProtocolRequestPacket) HANDSHAKE.add(::ProtocolResponsePacket) - LEGACY.skip() // ProtocolRequest - LEGACY.skip() // ProtocolResponse + // legacy protocol handshake looks like this + // --> ProtocolRequest + // <-- ProtocolResponse + // --> ClientConnect + // <-- HandshakeChallenge * + // --> HandshakeResponse * + // <-- ConnectSuccess / ConnectFailure + + LEGACY.skip("ProtocolRequest") + LEGACY.skip("ProtocolResponse") // Packets sent universe server -> universe client LEGACY.add(::ServerDisconnectPacket) // ServerDisconnect LEGACY.add(::ConnectSuccessPacket) // ConnectSuccess - LEGACY.skip() // ConnectFailure + LEGACY.skip("ConnectFailure") LEGACY.add(::HandshakeChallengePacket) // HandshakeChallenge - LEGACY.skip() // ChatReceive - LEGACY.skip() // UniverseTimeUpdate - LEGACY.skip() // CelestialResponse - LEGACY.skip() // PlayerWarpResult - LEGACY.skip() // PlanetTypeUpdate - LEGACY.skip() // Pause - LEGACY.skip() // ServerInfo + LEGACY.skip("ChatReceive") + LEGACY.skip("UniverseTimeUpdate") + LEGACY.skip("CelestialResponse") + LEGACY.skip("PlayerWarpResult") + LEGACY.skip("PlanetTypeUpdate") + LEGACY.skip("Pause") + LEGACY.skip("ServerInfo") // Packets sent universe client -> universe server LEGACY.add(::ClientConnectPacket) // ClientConnect - LEGACY.skip() // ClientDisconnectRequest + LEGACY.skip("ClientDisconnectRequest") LEGACY.add(::HandshakeResponsePacket) // HandshakeResponse - LEGACY.skip() // PlayerWarp - LEGACY.skip() // FlyShip - LEGACY.skip() // ChatSend - LEGACY.skip() // CelestialRequest + LEGACY.skip("PlayerWarp") + LEGACY.skip("FlyShip") + LEGACY.skip("ChatSend") + LEGACY.skip("CelestialRequest") // Packets sent bidirectionally between the universe client and the universe // server - LEGACY.skip() // ClientContextUpdate + LEGACY.skip("ClientContextUpdate") // Packets sent world server -> world client - LEGACY.skip() // WorldStart - LEGACY.skip() // WorldStop - LEGACY.skip() // WorldLayoutUpdate - LEGACY.skip() // WorldParametersUpdate - LEGACY.skip() // CentralStructureUpdate - LEGACY.skip() // TileArrayUpdate - LEGACY.skip() // TileUpdate - LEGACY.skip() // TileLiquidUpdate - LEGACY.skip() // TileDamageUpdate - LEGACY.skip() // TileModificationFailure - LEGACY.skip() // GiveItem - LEGACY.skip() // EnvironmentUpdate - LEGACY.skip() // UpdateTileProtection - LEGACY.skip() // SetDungeonGravity - LEGACY.skip() // SetDungeonBreathable - LEGACY.skip() // SetPlayerStart - LEGACY.skip() // FindUniqueEntityResponse - LEGACY.skip() // Pong + LEGACY.add(::WorldStartPacket) // WorldStart + LEGACY.skip("WorldStop") + LEGACY.skip("WorldLayoutUpdate") + LEGACY.skip("WorldParametersUpdate") + LEGACY.skip("CentralStructureUpdate") + LEGACY.skip("TileArrayUpdate") + LEGACY.skip("TileUpdate") + LEGACY.skip("TileLiquidUpdate") + LEGACY.skip("TileDamageUpdate") + LEGACY.skip("TileModificationFailure") + LEGACY.skip("GiveItem") + LEGACY.skip("EnvironmentUpdate") + LEGACY.skip("UpdateTileProtection") + LEGACY.skip("SetDungeonGravity") + LEGACY.skip("SetDungeonBreathable") + LEGACY.skip("SetPlayerStart") + LEGACY.skip("FindUniqueEntityResponse") + LEGACY.skip("Pong") // Packets sent world client -> world server - LEGACY.skip() // ModifyTileList - LEGACY.skip() // DamageTileGroup - LEGACY.skip() // CollectLiquid - LEGACY.skip() // RequestDrop - LEGACY.skip() // SpawnEntity - LEGACY.skip() // ConnectWire - LEGACY.skip() // DisconnectAllWires - LEGACY.skip() // WorldClientStateUpdate - LEGACY.skip() // FindUniqueEntity - LEGACY.skip() // WorldStartAcknowledge - LEGACY.skip() // Ping + LEGACY.skip("ModifyTileList") + LEGACY.skip("DamageTileGroup") + LEGACY.skip("CollectLiquid") + LEGACY.skip("RequestDrop") + LEGACY.skip("SpawnEntity") + LEGACY.skip("ConnectWire") + LEGACY.skip("DisconnectAllWires") + LEGACY.skip("WorldClientStateUpdate") + LEGACY.skip("FindUniqueEntity") + LEGACY.skip("WorldStartAcknowledge") + LEGACY.skip("Ping") // Packets sent bidirectionally between world client and world server - LEGACY.skip() // EntityCreate - LEGACY.skip() // EntityUpdateSet - LEGACY.skip() // EntityDestroy - LEGACY.skip() // EntityInteract - LEGACY.skip() // EntityInteractResult - LEGACY.skip() // HitRequest - LEGACY.skip() // DamageRequest - LEGACY.skip() // DamageNotification - LEGACY.skip() // EntityMessage - LEGACY.skip() // EntityMessageResponse - LEGACY.skip() // UpdateWorldProperties - LEGACY.skip() // StepUpdate + LEGACY.skip("EntityCreate") + LEGACY.skip("EntityUpdateSet") + LEGACY.skip("EntityDestroy") + LEGACY.skip("EntityInteract") + LEGACY.skip("EntityInteractResult") + LEGACY.skip("HitRequest") + LEGACY.skip("DamageRequest") + LEGACY.skip("DamageNotification") + LEGACY.skip("EntityMessage") + LEGACY.skip("EntityMessageResponse") + LEGACY.skip("UpdateWorldProperties") + LEGACY.skip("StepUpdate") // Packets sent system server -> system client - LEGACY.skip() // SystemWorldStart - LEGACY.skip() // SystemWorldUpdate - LEGACY.skip() // SystemObjectCreate - LEGACY.skip() // SystemObjectDestroy - LEGACY.skip() // SystemShipCreate - LEGACY.skip() // SystemShipDestroy + LEGACY.skip("SystemWorldStart") + LEGACY.skip("SystemWorldUpdate") + LEGACY.skip("SystemObjectCreate") + LEGACY.skip("SystemObjectDestroy") + LEGACY.skip("SystemShipCreate") + LEGACY.skip("SystemShipDestroy") // Packets sent system client -> system server - LEGACY.skip() // SystemObjectSpawn + LEGACY.skip("SystemObjectSpawn") } } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/ProtocolResponsePacket.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/ProtocolResponsePacket.kt index 9c3710bb..d6b418d5 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/ProtocolResponsePacket.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/ProtocolResponsePacket.kt @@ -29,9 +29,9 @@ data class ProtocolResponsePacket(val allowed: Boolean) : IClientPacket { playerSpecies = "hylotl", shipChunks = HashMap(), shipUpgrades = ShipUpgrades(), - introComplete = false, + introComplete = true, account = "" - ) + ) ) } else { connection.setupNative() diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/clientbound/ConnectSuccessPacket.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/clientbound/ConnectSuccessPacket.kt index 1d8678a6..5f4f7761 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/clientbound/ConnectSuccessPacket.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/clientbound/ConnectSuccessPacket.kt @@ -1,7 +1,9 @@ package ru.dbotthepony.kstarbound.network.packets.clientbound import ru.dbotthepony.kommons.io.readUUID +import ru.dbotthepony.kommons.io.readVarInt import ru.dbotthepony.kommons.io.writeUUID +import ru.dbotthepony.kommons.io.writeVarInt import ru.dbotthepony.kstarbound.client.ClientConnection import ru.dbotthepony.kstarbound.defs.CelestialBaseInformation import ru.dbotthepony.kstarbound.network.IClientPacket @@ -11,18 +13,18 @@ import java.util.UUID class ConnectSuccessPacket(val connectionID: Int, val serverUUID: UUID, val celestialInformation: CelestialBaseInformation) : IClientPacket { constructor(stream: DataInputStream, isLegacy: Boolean) : this( - stream.readUnsignedShort(), + stream.readVarInt(), stream.readUUID(), CelestialBaseInformation(stream, isLegacy) ) override fun write(stream: DataOutputStream, isLegacy: Boolean) { - stream.writeShort(connectionID) + stream.writeVarInt(connectionID) stream.writeUUID(serverUUID) celestialInformation.write(stream, isLegacy) } override fun play(connection: ClientConnection) { - TODO("Not yet implemented") + connection.connectionID = connectionID } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/clientbound/WorldStartPacket.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/clientbound/WorldStartPacket.kt new file mode 100644 index 00000000..6a50fc41 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/clientbound/WorldStartPacket.kt @@ -0,0 +1,77 @@ +package ru.dbotthepony.kstarbound.network.packets.clientbound + +import com.google.gson.JsonElement +import it.unimi.dsi.fastutil.ints.Int2BooleanAVLTreeMap +import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap +import it.unimi.dsi.fastutil.ints.IntAVLTreeSet +import ru.dbotthepony.kommons.io.readByteArray +import ru.dbotthepony.kommons.io.readCollection +import ru.dbotthepony.kommons.io.readMap +import ru.dbotthepony.kommons.io.readVector2d +import ru.dbotthepony.kommons.io.readVector2f +import ru.dbotthepony.kommons.io.writeByteArray +import ru.dbotthepony.kommons.io.writeCollection +import ru.dbotthepony.kommons.io.writeMap +import ru.dbotthepony.kommons.io.writeStruct2d +import ru.dbotthepony.kommons.io.writeStruct2f +import ru.dbotthepony.kommons.vector.Vector2d +import ru.dbotthepony.kstarbound.client.ClientConnection +import ru.dbotthepony.kstarbound.json.readJsonElement +import ru.dbotthepony.kstarbound.json.writeJsonElement +import ru.dbotthepony.kstarbound.network.IClientPacket +import java.io.DataInputStream +import java.io.DataOutputStream + +class WorldStartPacket( + val templateData: JsonElement, val skyData: ByteArray, val weatherData: ByteArray, + val playerStart: Vector2d, val playerRespawn: Vector2d, val respawnInWorld: Boolean, + val dungeonGravity: Map, val dungeonBreathable: Map, + val protectedDungeonIDs: Set, val worldProperties: JsonElement, val connectionID: Int, + val localInterpolationMode: Boolean, +) : IClientPacket { + constructor(stream: DataInputStream, isLegacy: Boolean) : this( + stream.readJsonElement(), + stream.readByteArray(), + stream.readByteArray(), + if (isLegacy) stream.readVector2f().toDoubleVector() else stream.readVector2d(), + if (isLegacy) stream.readVector2f().toDoubleVector() else stream.readVector2d(), + stream.readBoolean(), + if (isLegacy) stream.readMap({ readUnsignedShort() }, { Vector2d(0.0, readFloat().toDouble()) }, ::Int2ObjectOpenHashMap) else stream.readMap({ readInt() }, { readVector2d() }, { Int2ObjectAVLTreeMap() }), + if (isLegacy) stream.readMap({ readUnsignedShort() }, { readBoolean() }, ::Int2ObjectOpenHashMap) else stream.readMap({ readInt() }, { readBoolean() }, { Int2BooleanAVLTreeMap() }), + if (isLegacy) stream.readCollection({ readUnsignedShort() }, { IntAVLTreeSet() }) else stream.readCollection({ readInt() }, { IntAVLTreeSet() }), + stream.readJsonElement(), + stream.readUnsignedShort(), + stream.readBoolean() + ) + + override fun write(stream: DataOutputStream, isLegacy: Boolean) { + stream.writeJsonElement(templateData) + stream.writeByteArray(skyData) + stream.writeByteArray(weatherData) + + if (isLegacy) { + stream.writeStruct2f(playerStart.toFloatVector()) + stream.writeStruct2f(playerRespawn.toFloatVector()) + stream.writeBoolean(respawnInWorld) + stream.writeMap(dungeonGravity, { writeShort(it) }, { writeFloat(it.y.toFloat()) }) + stream.writeMap(dungeonBreathable, { writeShort(it) }, { writeBoolean(it) }) + stream.writeCollection(protectedDungeonIDs) { writeShort(it) } + } else { + stream.writeStruct2d(playerStart) + stream.writeStruct2d(playerRespawn) + stream.writeBoolean(respawnInWorld) + stream.writeMap(dungeonGravity, { writeInt(it) }, { writeStruct2d(it) }) + stream.writeMap(dungeonBreathable, { writeInt(it) }, { writeBoolean(it) }) + stream.writeCollection(protectedDungeonIDs) { writeInt(it) } + } + + stream.writeJsonElement(worldProperties) + stream.writeShort(connectionID) + stream.writeBoolean(localInterpolationMode) + } + + override fun play(connection: ClientConnection) { + TODO("Not yet implemented") + } +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/serverbound/ClientConnectPacket.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/serverbound/ClientConnectPacket.kt index d41df676..2866c09d 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/serverbound/ClientConnectPacket.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/serverbound/ClientConnectPacket.kt @@ -39,7 +39,7 @@ data class ClientConnectPacket( stream.readBinaryString(), stream.readBinaryString(), stream.readMap(InputStream::readByteKey, { readKOptional { readByteArray() } }, { HashMap(it) }), - ShipUpgrades.read(stream, isLegacy), + ShipUpgrades(stream, isLegacy), stream.readBoolean(), stream.readBinaryString() ) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/server/network/packets/TrackedPositionPacket.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/server/network/packets/TrackedPositionPacket.kt index 35c899d7..5efad3cd 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/server/network/packets/TrackedPositionPacket.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/server/network/packets/TrackedPositionPacket.kt @@ -1,18 +1,18 @@ package ru.dbotthepony.kstarbound.server.network.packets +import ru.dbotthepony.kommons.io.readVector2d +import ru.dbotthepony.kommons.io.writeStruct2d import ru.dbotthepony.kommons.vector.Vector2d import ru.dbotthepony.kstarbound.network.IServerPacket import ru.dbotthepony.kstarbound.server.ServerConnection -import ru.dbotthepony.kstarbound.io.readVec2d -import ru.dbotthepony.kstarbound.io.writeVec2d import java.io.DataInputStream import java.io.DataOutputStream data class TrackedPositionPacket(val pos: Vector2d) : IServerPacket { - constructor(stream: DataInputStream, isLegacy: Boolean) : this(stream.readVec2d()) + constructor(stream: DataInputStream, isLegacy: Boolean) : this(stream.readVector2d()) override fun write(stream: DataOutputStream, isLegacy: Boolean) { - stream.writeVec2d(pos) + stream.writeStruct2d(pos) } override fun play(connection: ServerConnection) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/WorldGeometry.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/WorldGeometry.kt index 3a96ca4d..8d09e95e 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/WorldGeometry.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/WorldGeometry.kt @@ -1,23 +1,23 @@ package ru.dbotthepony.kstarbound.world +import ru.dbotthepony.kommons.io.readVector2i +import ru.dbotthepony.kommons.io.writeStruct2i import ru.dbotthepony.kommons.util.IStruct2d import ru.dbotthepony.kommons.util.IStruct2f import ru.dbotthepony.kommons.util.IStruct2i import ru.dbotthepony.kommons.vector.Vector2d import ru.dbotthepony.kommons.vector.Vector2i -import ru.dbotthepony.kstarbound.io.readVec2i -import ru.dbotthepony.kstarbound.io.writeVec2i import java.io.DataInputStream import java.io.DataOutputStream data class WorldGeometry(val size: Vector2i, val loopX: Boolean, val loopY: Boolean) { - constructor(buff: DataInputStream) : this(buff.readVec2i(), buff.readBoolean(), buff.readBoolean()) + constructor(buff: DataInputStream) : this(buff.readVector2i(), buff.readBoolean(), buff.readBoolean()) val x: CoordinateMapper = if (loopX) CoordinateMapper.Wrapper(size.x) else CoordinateMapper.Clamper(size.x) val y: CoordinateMapper = if (loopY) CoordinateMapper.Wrapper(size.y) else CoordinateMapper.Clamper(size.y) fun write(buff: DataOutputStream) { - buff.writeVec2i(size) + buff.writeStruct2i(size) buff.writeBoolean(loopX) buff.writeBoolean(loopY) }