More work on legacy protocol

This commit is contained in:
DBotThePony 2024-02-12 16:06:51 +07:00
parent c2dc7c2e11
commit fd233b9ab5
Signed by: DBot
GPG Key ID: DCC23B5715498507
17 changed files with 209 additions and 122 deletions

View File

@ -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

View File

@ -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))
}

View File

@ -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() {
}

View File

@ -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<ImmutableCell>) : IClie
})
override fun write(stream: DataOutputStream, isLegacy: Boolean) {
stream.writeVec2i(pos)
stream.writeStruct2i(pos)
stream.writeCollection(data) { it.write(stream) }
}

View File

@ -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) {

View File

@ -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) {

View File

@ -19,6 +19,15 @@ data class ShipUpgrades(
val shipSpeed: Int = 0,
val capabilities: ImmutableSet<String> = 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() })
)
}
}
}

View File

@ -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())
}

View File

@ -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

View File

@ -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)

View File

@ -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<Type<*>?>()
private val missingNames = Int2ObjectArrayMap<String>()
private val clazz2Type = Reference2ObjectOpenHashMap<KClass<*>, Type<*>>()
private data class Type<T : IPacket>(val id: Int, val type: KClass<T>, val factory: IPacketReader<T>, 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")
}
}
}

View File

@ -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()

View File

@ -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
}
}

View File

@ -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<Int, Vector2d>, val dungeonBreathable: Map<Int, Boolean>,
val protectedDungeonIDs: Set<Int>, 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")
}
}

View File

@ -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()
)

View File

@ -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) {

View File

@ -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)
}