mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-19 18:14:44 +00:00
Refactor all packet definitions out of PSPacket
This commit is contained in:
parent
f81d67f959
commit
83da72e50e
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import scodec.bits._
|
||||
|
||||
final case class ClientChallengeXchg(time : Long, challenge : ByteVector, p : ByteVector, g : ByteVector)
|
||||
extends PlanetSideCryptoPacket {
|
||||
def opcode = CryptoPacketOpcode.ClientChallengeXchg
|
||||
def encode = ClientChallengeXchg.encode(this)
|
||||
}
|
||||
|
||||
object ClientChallengeXchg extends Marshallable[ClientChallengeXchg] {
|
||||
implicit val codec: Codec[ClientChallengeXchg] = (
|
||||
("unknown" | constant(1)) ::
|
||||
("unknown" | constant(1)) ::
|
||||
("client_time" | uint32L) ::
|
||||
("challenge" | bytes(12)) ::
|
||||
("end_chal?" | constant(0)) ::
|
||||
("objects?" | constant(1)) ::
|
||||
("object_type?" | constant(hex"0002".bits)) ::
|
||||
("unknown" | constant(hex"ff240000".bits)) ::
|
||||
("P_len" | constant(hex"1000".bits)) ::
|
||||
("P" | bytes(16)) ::
|
||||
("G_len" | constant(hex"1000".bits)) ::
|
||||
("G" | bytes(16)) ::
|
||||
("end?" | constant(0)) ::
|
||||
("end?" | constant(0)) ::
|
||||
("objects?" | constant(1)) ::
|
||||
("unknown" | constant(hex"03070000".bits)) ::
|
||||
("end?" | constant(0))
|
||||
).as[ClientChallengeXchg]
|
||||
}
|
||||
24
common/src/main/scala/psforever/net/ClientFinished.scala
Normal file
24
common/src/main/scala/psforever/net/ClientFinished.scala
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import scodec.bits._
|
||||
|
||||
final case class ClientFinished(pubKey : ByteVector, challengeResult: ByteVector)
|
||||
extends PlanetSideCryptoPacket {
|
||||
type Packet = ClientFinished
|
||||
def opcode = CryptoPacketOpcode.ClientFinished
|
||||
def encode = ClientFinished.encode(this)
|
||||
}
|
||||
|
||||
object ClientFinished extends Marshallable[ClientFinished] {
|
||||
implicit val codec : Codec[ClientFinished] = (
|
||||
("obj_type?" | constant(hex"10".bits)) ::
|
||||
("pub_key_len" | constant(hex"1000")) ::
|
||||
("pub_key" | bytes(16)) ::
|
||||
("unknown" | constant(hex"0114".bits)) ::
|
||||
("challenge_result" | bytes(0xc))
|
||||
).as[ClientFinished]
|
||||
}
|
||||
21
common/src/main/scala/psforever/net/ClientStart.scala
Normal file
21
common/src/main/scala/psforever/net/ClientStart.scala
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import scodec.bits._
|
||||
|
||||
final case class ClientStart(clientNonce : Long)
|
||||
extends PlanetSideControlPacket {
|
||||
type Packet = ClientStart
|
||||
def opcode = ControlPacketOpcode.ClientStart
|
||||
def encode = ClientStart.encode(this)
|
||||
}
|
||||
|
||||
object ClientStart extends Marshallable[ClientStart] {
|
||||
implicit val codec : Codec[ClientStart] = (
|
||||
("unknown" | constant(hex"00000002".bits)) ::
|
||||
("client_nonce" | uint32L) ::
|
||||
("unknown" | constant(hex"000001f0".bits))
|
||||
).as[ClientStart]
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
|
||||
final case class ConnectToWorldMessage(world : String)
|
||||
extends PlanetSideGamePacket {
|
||||
type Packet = ConnectToWorldMessage
|
||||
def opcode = GamePacketOpcode.ConnectToWorldMessage
|
||||
def encode = ConnectToWorldMessage.encode(this)
|
||||
}
|
||||
|
||||
object ConnectToWorldMessage extends Marshallable[ConnectToWorldMessage] {
|
||||
implicit val codec : Codec[ConnectToWorldMessage] = ascii.as[ConnectToWorldMessage]
|
||||
}
|
||||
15
common/src/main/scala/psforever/net/ConnectionClose.scala
Normal file
15
common/src/main/scala/psforever/net/ConnectionClose.scala
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.Codec
|
||||
|
||||
final case class ConnectionClose()
|
||||
extends PlanetSideControlPacket {
|
||||
type Packet = ConnectionClose
|
||||
def opcode = ControlPacketOpcode.ConnectionClose
|
||||
def encode = ConnectionClose.encode(this)
|
||||
}
|
||||
|
||||
object ConnectionClose extends Marshallable[ConnectionClose] {
|
||||
implicit val codec: Codec[ConnectionClose] = PacketHelpers.emptyCodec(ConnectionClose())
|
||||
}
|
||||
16
common/src/main/scala/psforever/net/HandleGamePacket.scala
Normal file
16
common/src/main/scala/psforever/net/HandleGamePacket.scala
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
|
||||
final case class HandleGamePacket(packet : ByteVector)
|
||||
extends PlanetSideControlPacket {
|
||||
def opcode = ControlPacketOpcode.HandleGamePacket
|
||||
def encode = throw new Exception("This packet type should never be encoded")
|
||||
}
|
||||
|
||||
object HandleGamePacket extends Marshallable[HandleGamePacket] {
|
||||
implicit val codec : Codec[HandleGamePacket] = bytes.as[HandleGamePacket].decodeOnly
|
||||
}
|
||||
72
common/src/main/scala/psforever/net/LoginMessage.scala
Normal file
72
common/src/main/scala/psforever/net/LoginMessage.scala
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import scodec.bits._
|
||||
import shapeless._
|
||||
|
||||
final case class LoginMessage(majorVersion : Long,
|
||||
minorVersion : Long,
|
||||
buildDate : String,
|
||||
username : String,
|
||||
password : Option[String],
|
||||
token : Option[String],
|
||||
revision : Long) extends PlanetSideGamePacket {
|
||||
require(majorVersion >= 0)
|
||||
require(minorVersion >= 0)
|
||||
require(revision >= 0)
|
||||
require(password.isDefined ^ token.isDefined, "Either 'username' or 'token' must be set, but not both")
|
||||
|
||||
def opcode = GamePacketOpcode.LoginMessage
|
||||
def encode = LoginMessage.encode(this)
|
||||
}
|
||||
|
||||
object LoginMessage extends Marshallable[LoginMessage] {
|
||||
private def username = PacketHelpers.encodedStringAligned(7)
|
||||
private def password = PacketHelpers.encodedString
|
||||
private def tokenPath = fixedSizeBytes(32, ascii) :: username
|
||||
private def passwordPath = username :: password
|
||||
|
||||
type Struct = String :: Option[String] :: Option[String] :: HNil
|
||||
|
||||
/* Okay, okay, here's what's happening here:
|
||||
|
||||
PlanetSide's *wonderful* packet design reuses packets for different encodings.
|
||||
What we have here is that depending on a boolean in the LoginPacket, we will either
|
||||
be decoding a username & password OR a token & username. Yeah...so this doesn't
|
||||
really fit in to a fixed packet decoding scheme.
|
||||
|
||||
The below code abstracts away from this by using pattern matching.
|
||||
The scodec specific part is the either(...) Codec, which decodes one bit and chooses
|
||||
Left or Right depending on it.
|
||||
*/
|
||||
implicit val credentialChoice : Codec[Struct] = {
|
||||
type InStruct = Either[String :: String :: HNil, String :: String :: HNil]
|
||||
|
||||
def from(a : InStruct) : Struct = a match {
|
||||
case Left(username :: password :: HNil) => username :: Some(password) :: None :: HNil
|
||||
case Right(token :: username :: HNil) => username :: None :: Some(token) :: HNil
|
||||
}
|
||||
|
||||
// serialization can fail if the user did not specify a token or password (or both)
|
||||
def to(a : Struct) : InStruct = a match {
|
||||
case username :: Some(password) :: None :: HNil => Left(username :: password :: HNil)
|
||||
case username :: None :: Some(token) :: HNil => Right(token :: username :: HNil)
|
||||
}
|
||||
|
||||
either(bool, passwordPath, tokenPath).xmap[Struct](from, to)
|
||||
}
|
||||
|
||||
implicit val codec : Codec[LoginMessage] = (
|
||||
("major_version" | uint32L) ::
|
||||
("minor_version" | uint32L) ::
|
||||
("build_date" | PacketHelpers.encodedString) ::
|
||||
(
|
||||
// The :+ operator (and the parens) are required because we are adding an HList to an HList,
|
||||
// not merely a value (like bool). Weird shit, but hey this works.
|
||||
("credential_choice" | credentialChoice) :+
|
||||
("revision" | uint32L)
|
||||
)
|
||||
).as[LoginMessage]
|
||||
}
|
||||
34
common/src/main/scala/psforever/net/LoginRespMessage.scala
Normal file
34
common/src/main/scala/psforever/net/LoginRespMessage.scala
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import scodec.bits._
|
||||
|
||||
final case class LoginRespMessage(token : String, // printable ascii for 16
|
||||
unknown : ByteVector, // hex"00000000 18FABE0C 00000000 00000000"
|
||||
error : Long, // 0
|
||||
stationError : Long, // 1
|
||||
subscriptionStatus : Long, // 2 or 5
|
||||
someToken : Long, // 685276011
|
||||
username : String, // the user
|
||||
unk5 : Long, // 0 and unset bool
|
||||
someBit : Boolean) extends PlanetSideGamePacket {
|
||||
def opcode = GamePacketOpcode.LoginRespMessage
|
||||
def encode = LoginRespMessage.encode(this)
|
||||
}
|
||||
|
||||
object LoginRespMessage extends Marshallable[LoginRespMessage] {
|
||||
implicit val codec : Codec[LoginRespMessage] = (
|
||||
("token" | fixedSizeBytes(16, ascii)) ::
|
||||
("unknown" | bytes(16)) ::
|
||||
("error" | uint32L) ::
|
||||
("station_error" | uint32L) ::
|
||||
("subscription_status" | uint32L) ::
|
||||
("unknown" | uint32L) ::
|
||||
("username" | PacketHelpers.encodedString) ::
|
||||
("unknown" | uint32L) ::
|
||||
("unknown" | byteAligned(bool))
|
||||
).as[LoginRespMessage]
|
||||
}
|
||||
18
common/src/main/scala/psforever/net/MultiPacket.scala
Normal file
18
common/src/main/scala/psforever/net/MultiPacket.scala
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import scodec.bits._
|
||||
|
||||
final case class MultiPacket(packets : Vector[ByteVector])
|
||||
extends PlanetSideControlPacket {
|
||||
type Packet = MultiPacket
|
||||
def opcode = ControlPacketOpcode.MultiPacket
|
||||
def encode = MultiPacket.encode(this)
|
||||
}
|
||||
|
||||
object MultiPacket extends Marshallable[MultiPacket] {
|
||||
implicit val codec : Codec[MultiPacket] = ("packets" | vector(variableSizeBytes(uint8L, bytes))).as[MultiPacket]
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import scodec.bits._
|
|||
import scodec.codecs._
|
||||
import scodec._
|
||||
import shapeless._
|
||||
import shapeless.ops.hlist.Prepend
|
||||
|
||||
// Base packets
|
||||
sealed trait PlanetSidePacket extends Serializable {
|
||||
|
|
@ -36,283 +35,6 @@ trait PlanetSideCryptoPacket extends PlanetSidePacket {
|
|||
def opcode : CryptoPacketOpcode.Type
|
||||
}
|
||||
|
||||
// Crypto Packets
|
||||
final case class ClientChallengeXchg(time : Long, challenge : ByteVector, p : ByteVector, g : ByteVector)
|
||||
extends PlanetSideCryptoPacket {
|
||||
def opcode = CryptoPacketOpcode.ClientChallengeXchg
|
||||
def encode = ClientChallengeXchg.encode(this)
|
||||
}
|
||||
|
||||
object ClientChallengeXchg extends Marshallable[ClientChallengeXchg] {
|
||||
implicit val codec: Codec[ClientChallengeXchg] = (
|
||||
("unknown" | constant(1)) ::
|
||||
("unknown" | constant(1)) ::
|
||||
("client_time" | uint32L) ::
|
||||
("challenge" | bytes(12)) ::
|
||||
("end_chal?" | constant(0)) ::
|
||||
("objects?" | constant(1)) ::
|
||||
("object_type?" | constant(hex"0002".bits)) ::
|
||||
("unknown" | constant(hex"ff240000".bits)) ::
|
||||
("P_len" | constant(hex"1000".bits)) ::
|
||||
("P" | bytes(16)) ::
|
||||
("G_len" | constant(hex"1000".bits)) ::
|
||||
("G" | bytes(16)) ::
|
||||
("end?" | constant(0)) ::
|
||||
("end?" | constant(0)) ::
|
||||
("objects?" | constant(1)) ::
|
||||
("unknown" | constant(hex"03070000".bits)) ::
|
||||
("end?" | constant(0))
|
||||
).as[ClientChallengeXchg]
|
||||
}
|
||||
|
||||
final case class ServerChallengeXchg(time : Long, challenge : ByteVector, pubKey : ByteVector)
|
||||
extends PlanetSideCryptoPacket {
|
||||
type Packet = ServerChallengeXchg
|
||||
def opcode = CryptoPacketOpcode.ServerChallengeXchg
|
||||
def encode = ServerChallengeXchg.encode(this)
|
||||
}
|
||||
|
||||
object ServerChallengeXchg extends Marshallable[ServerChallengeXchg] {
|
||||
def getCompleteChallenge(time : Long, rest : ByteVector): ByteVector =
|
||||
uint32L.encode(time).require.toByteVector ++ rest
|
||||
|
||||
implicit val codec: Codec[ServerChallengeXchg] = (
|
||||
("unknown" | constant(2)) ::
|
||||
("unknown" | constant(1)) ::
|
||||
("server_time" | uint32L) ::
|
||||
("challenge" | bytes(0xC)) ::
|
||||
("end?" | constant(0)) ::
|
||||
("objects" | constant(1)) ::
|
||||
("unknown" | constant(hex"03070000000c00".bits)) ::
|
||||
("pub_key_len" | constant(hex"1000")) ::
|
||||
("pub_key" | bytes(16)) ::
|
||||
("unknown" | constant(0x0e))
|
||||
).as[ServerChallengeXchg]
|
||||
}
|
||||
|
||||
final case class ClientFinished(pubKey : ByteVector, challengeResult: ByteVector)
|
||||
extends PlanetSideCryptoPacket {
|
||||
type Packet = ClientFinished
|
||||
def opcode = CryptoPacketOpcode.ClientFinished
|
||||
def encode = ClientFinished.encode(this)
|
||||
}
|
||||
|
||||
object ClientFinished extends Marshallable[ClientFinished] {
|
||||
implicit val codec : Codec[ClientFinished] = (
|
||||
("obj_type?" | constant(hex"10".bits)) ::
|
||||
("pub_key_len" | constant(hex"1000")) ::
|
||||
("pub_key" | bytes(16)) ::
|
||||
("unknown" | constant(hex"0114".bits)) ::
|
||||
("challenge_result" | bytes(0xc))
|
||||
).as[ClientFinished]
|
||||
}
|
||||
|
||||
final case class ServerFinished(challengeResult : ByteVector)
|
||||
extends PlanetSideCryptoPacket {
|
||||
type Packet = ServerFinished
|
||||
def opcode = CryptoPacketOpcode.ServerFinished
|
||||
def encode = ServerFinished.encode(this)
|
||||
}
|
||||
|
||||
object ServerFinished extends Marshallable[ServerFinished] {
|
||||
implicit val codec : Codec[ServerFinished] = (
|
||||
("unknown" | constant(hex"0114".bits)) ::
|
||||
("challenge_result" | bytes(0xc))
|
||||
).as[ServerFinished]
|
||||
}
|
||||
|
||||
// Game Packets
|
||||
final case class LoginMessage(majorVersion : Long,
|
||||
minorVersion : Long,
|
||||
buildDate : String,
|
||||
username : String,
|
||||
password : Option[String],
|
||||
token : Option[String],
|
||||
revision : Long) extends PlanetSideGamePacket {
|
||||
require(majorVersion >= 0)
|
||||
require(minorVersion >= 0)
|
||||
require(revision >= 0)
|
||||
require(password.isDefined ^ token.isDefined, "Either 'username' or 'token' must be set, but not both")
|
||||
|
||||
def opcode = GamePacketOpcode.LoginMessage
|
||||
def encode = LoginMessage.encode(this)
|
||||
}
|
||||
|
||||
object LoginMessage extends Marshallable[LoginMessage] {
|
||||
private def username = PacketHelpers.encodedStringAligned(7)
|
||||
private def password = PacketHelpers.encodedString
|
||||
private def tokenPath = fixedSizeBytes(32, ascii) :: username
|
||||
private def passwordPath = username :: password
|
||||
|
||||
type Struct = String :: Option[String] :: Option[String] :: HNil
|
||||
|
||||
/* Okay, okay, here's what's happening here:
|
||||
|
||||
PlanetSide's *wonderful* packet design reuses packets for different encodings.
|
||||
What we have here is that depending on a boolean in the LoginPacket, we will either
|
||||
be decoding a username & password OR a token & username. Yeah...so this doesn't
|
||||
really fit in to a fixed packet decoding scheme.
|
||||
|
||||
The below code abstracts away from this by using pattern matching.
|
||||
The scodec specific part is the either(...) Codec, which decodes one bit and chooses
|
||||
Left or Right depending on it.
|
||||
*/
|
||||
implicit val credentialChoice : Codec[Struct] = {
|
||||
type InStruct = Either[String :: String :: HNil, String :: String :: HNil]
|
||||
|
||||
def from(a : InStruct) : Struct = a match {
|
||||
case Left(username :: password :: HNil) => username :: Some(password) :: None :: HNil
|
||||
case Right(token :: username :: HNil) => username :: None :: Some(token) :: HNil
|
||||
}
|
||||
|
||||
// serialization can fail if the user did not specify a token or password (or both)
|
||||
def to(a : Struct) : InStruct = a match {
|
||||
case username :: Some(password) :: None :: HNil => Left(username :: password :: HNil)
|
||||
case username :: None :: Some(token) :: HNil => Right(token :: username :: HNil)
|
||||
}
|
||||
|
||||
either(bool, passwordPath, tokenPath).xmap[Struct](from, to)
|
||||
}
|
||||
|
||||
implicit val codec : Codec[LoginMessage] = (
|
||||
("major_version" | uint32L) ::
|
||||
("minor_version" | uint32L) ::
|
||||
("build_date" | PacketHelpers.encodedString) ::
|
||||
(
|
||||
// The :+ operator (and the parens) are required because we are adding an HList to an HList,
|
||||
// not merely a value (like bool). Weird shit, but hey this works.
|
||||
("credential_choice" | credentialChoice) :+
|
||||
("revision" | uint32L)
|
||||
)
|
||||
).as[LoginMessage]
|
||||
}
|
||||
|
||||
final case class LoginRespMessage(token : String, // printable ascii for 16
|
||||
unknown : ByteVector, // hex"00000000 18FABE0C 00000000 00000000"
|
||||
error : Long, // 0
|
||||
stationError : Long, // 1
|
||||
subscriptionStatus : Long, // 2 or 5
|
||||
someToken : Long, // 685276011
|
||||
username : String, // the user
|
||||
unk5 : Long, // 0 and unset bool
|
||||
someBit : Boolean) extends PlanetSideGamePacket {
|
||||
def opcode = GamePacketOpcode.LoginRespMessage
|
||||
def encode = LoginRespMessage.encode(this)
|
||||
}
|
||||
|
||||
object LoginRespMessage extends Marshallable[LoginRespMessage] {
|
||||
implicit val codec : Codec[LoginRespMessage] = (
|
||||
("token" | fixedSizeBytes(16, ascii)) ::
|
||||
("unknown" | bytes(16)) ::
|
||||
("error" | uint32L) ::
|
||||
("station_error" | uint32L) ::
|
||||
("subscription_status" | uint32L) ::
|
||||
("unknown" | uint32L) ::
|
||||
("username" | PacketHelpers.encodedString) ::
|
||||
("unknown" | uint32L) ::
|
||||
("unknown" | byteAligned(bool))
|
||||
).as[LoginRespMessage]
|
||||
}
|
||||
|
||||
final case class ConnectToWorldMessage(world : String)
|
||||
extends PlanetSideGamePacket {
|
||||
type Packet = ConnectToWorldMessage
|
||||
def opcode = GamePacketOpcode.ConnectToWorldMessage
|
||||
def encode = ConnectToWorldMessage.encode(this)
|
||||
}
|
||||
|
||||
object ConnectToWorldMessage extends Marshallable[ConnectToWorldMessage] {
|
||||
implicit val codec : Codec[ConnectToWorldMessage] = ascii.as[ConnectToWorldMessage]
|
||||
}
|
||||
|
||||
// Control Packets
|
||||
final case class HandleGamePacket(packet : ByteVector)
|
||||
extends PlanetSideControlPacket {
|
||||
def opcode = ControlPacketOpcode.HandleGamePacket
|
||||
def encode = throw new Exception("This packet type should never be encoded")
|
||||
}
|
||||
|
||||
object HandleGamePacket extends Marshallable[HandleGamePacket] {
|
||||
implicit val codec : Codec[HandleGamePacket] = bytes.as[HandleGamePacket].decodeOnly
|
||||
}
|
||||
|
||||
final case class ClientStart(clientNonce : Long)
|
||||
extends PlanetSideControlPacket {
|
||||
type Packet = ClientStart
|
||||
def opcode = ControlPacketOpcode.ClientStart
|
||||
def encode = ClientStart.encode(this)
|
||||
}
|
||||
|
||||
object ClientStart extends Marshallable[ClientStart] {
|
||||
implicit val codec : Codec[ClientStart] = (
|
||||
("unknown" | constant(hex"00000002".bits)) ::
|
||||
("client_nonce" | uint32L) ::
|
||||
("unknown" | constant(hex"000001f0".bits))
|
||||
).as[ClientStart]
|
||||
}
|
||||
|
||||
final case class ServerStart(clientNonce : Long, serverNonce : Long)
|
||||
extends PlanetSideControlPacket {
|
||||
type Packet = ServerStart
|
||||
def opcode = ControlPacketOpcode.ServerStart
|
||||
def encode = ServerStart.encode(this)
|
||||
}
|
||||
|
||||
object ServerStart extends Marshallable[ServerStart] {
|
||||
implicit val codec : Codec[ServerStart] = (
|
||||
("client_nonce" | uint32L) ::
|
||||
("server_nonce" | uint32L) ::
|
||||
("unknown" | constant(hex"000000000001d300000002".bits))
|
||||
).as[ServerStart]
|
||||
}
|
||||
|
||||
final case class MultiPacket(packets : Vector[ByteVector])
|
||||
extends PlanetSideControlPacket {
|
||||
type Packet = MultiPacket
|
||||
def opcode = ControlPacketOpcode.MultiPacket
|
||||
def encode = MultiPacket.encode(this)
|
||||
}
|
||||
|
||||
object MultiPacket extends Marshallable[MultiPacket] {
|
||||
implicit val codec : Codec[MultiPacket] = ("packets" | vector(variableSizeBytes(uint8L, bytes))).as[MultiPacket]
|
||||
}
|
||||
|
||||
final case class SlottedMetaPacket(/*slot : Int,*/ packet : ByteVector)
|
||||
extends PlanetSideControlPacket {
|
||||
type Packet = SlottedMetaPacket
|
||||
|
||||
//assert(slot >= 0 && slot <= 7, "Slot number is out of range")
|
||||
|
||||
def opcode = {
|
||||
val base = ControlPacketOpcode.SlottedMetaPacket0.id
|
||||
ControlPacketOpcode(base/* + slot*/)
|
||||
}
|
||||
|
||||
def encode = SlottedMetaPacket.encode(this)
|
||||
}
|
||||
|
||||
object SlottedMetaPacket extends Marshallable[SlottedMetaPacket] {
|
||||
implicit val codec : Codec[SlottedMetaPacket] = (
|
||||
("unknown" | constant(0)) ::
|
||||
("unknown" | constant(0)) ::
|
||||
("rest" | bytes)
|
||||
).as[SlottedMetaPacket]
|
||||
}
|
||||
|
||||
final case class ConnectionClose()
|
||||
extends PlanetSideControlPacket {
|
||||
type Packet = ConnectionClose
|
||||
def opcode = ControlPacketOpcode.ConnectionClose
|
||||
def encode = ConnectionClose.encode(this)
|
||||
}
|
||||
|
||||
object ConnectionClose extends Marshallable[ConnectionClose] {
|
||||
implicit val codec: Codec[ConnectionClose] = PacketHelpers.emptyCodec(ConnectionClose())
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
// Packet typing
|
||||
final case class PlanetSidePacketFlags(packetType : PacketType.Value, secured : Boolean)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import scodec.bits._
|
||||
|
||||
final case class ServerChallengeXchg(time : Long, challenge : ByteVector, pubKey : ByteVector)
|
||||
extends PlanetSideCryptoPacket {
|
||||
type Packet = ServerChallengeXchg
|
||||
def opcode = CryptoPacketOpcode.ServerChallengeXchg
|
||||
def encode = ServerChallengeXchg.encode(this)
|
||||
}
|
||||
|
||||
object ServerChallengeXchg extends Marshallable[ServerChallengeXchg] {
|
||||
def getCompleteChallenge(time : Long, rest : ByteVector): ByteVector =
|
||||
uint32L.encode(time).require.toByteVector ++ rest
|
||||
|
||||
implicit val codec: Codec[ServerChallengeXchg] = (
|
||||
("unknown" | constant(2)) ::
|
||||
("unknown" | constant(1)) ::
|
||||
("server_time" | uint32L) ::
|
||||
("challenge" | bytes(0xC)) ::
|
||||
("end?" | constant(0)) ::
|
||||
("objects" | constant(1)) ::
|
||||
("unknown" | constant(hex"03070000000c00".bits)) ::
|
||||
("pub_key_len" | constant(hex"1000")) ::
|
||||
("pub_key" | bytes(16)) ::
|
||||
("unknown" | constant(0x0e))
|
||||
).as[ServerChallengeXchg]
|
||||
}
|
||||
21
common/src/main/scala/psforever/net/ServerFinished.scala
Normal file
21
common/src/main/scala/psforever/net/ServerFinished.scala
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import scodec.bits._
|
||||
|
||||
final case class ServerFinished(challengeResult : ByteVector)
|
||||
extends PlanetSideCryptoPacket {
|
||||
type Packet = ServerFinished
|
||||
def opcode = CryptoPacketOpcode.ServerFinished
|
||||
def encode = ServerFinished.encode(this)
|
||||
}
|
||||
|
||||
object ServerFinished extends Marshallable[ServerFinished] {
|
||||
implicit val codec : Codec[ServerFinished] = (
|
||||
("unknown" | constant(hex"0114".bits)) ::
|
||||
("challenge_result" | bytes(0xc))
|
||||
).as[ServerFinished]
|
||||
}
|
||||
21
common/src/main/scala/psforever/net/ServerStart.scala
Normal file
21
common/src/main/scala/psforever/net/ServerStart.scala
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import scodec.bits._
|
||||
|
||||
final case class ServerStart(clientNonce : Long, serverNonce : Long)
|
||||
extends PlanetSideControlPacket {
|
||||
type Packet = ServerStart
|
||||
def opcode = ControlPacketOpcode.ServerStart
|
||||
def encode = ServerStart.encode(this)
|
||||
}
|
||||
|
||||
object ServerStart extends Marshallable[ServerStart] {
|
||||
implicit val codec : Codec[ServerStart] = (
|
||||
("client_nonce" | uint32L) ::
|
||||
("server_nonce" | uint32L) ::
|
||||
("unknown" | constant(hex"000000000001d300000002".bits))
|
||||
).as[ServerStart]
|
||||
}
|
||||
28
common/src/main/scala/psforever/net/SlottedMetaPacket.scala
Normal file
28
common/src/main/scala/psforever/net/SlottedMetaPacket.scala
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package psforever.net
|
||||
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
|
||||
final case class SlottedMetaPacket(/*slot : Int,*/ packet : ByteVector)
|
||||
extends PlanetSideControlPacket {
|
||||
type Packet = SlottedMetaPacket
|
||||
|
||||
//assert(slot >= 0 && slot <= 7, "Slot number is out of range")
|
||||
|
||||
def opcode = {
|
||||
val base = ControlPacketOpcode.SlottedMetaPacket0.id
|
||||
ControlPacketOpcode(base/* + slot*/)
|
||||
}
|
||||
|
||||
def encode = SlottedMetaPacket.encode(this)
|
||||
}
|
||||
|
||||
object SlottedMetaPacket extends Marshallable[SlottedMetaPacket] {
|
||||
implicit val codec : Codec[SlottedMetaPacket] = (
|
||||
("unknown" | constant(0)) ::
|
||||
("unknown" | constant(0)) ::
|
||||
("rest" | bytes)
|
||||
).as[SlottedMetaPacket]
|
||||
}
|
||||
Loading…
Reference in a new issue