reset sequence at 0x8000, but only when retrieving a new sequence number; caching common flag values when marshalling packets

This commit is contained in:
Fate-JH 2026-04-14 15:11:05 -04:00
parent aac0ecfd3e
commit 5ce499672d
2 changed files with 28 additions and 21 deletions

View file

@ -222,7 +222,8 @@ class MiddlewareActor(
* @return next sequence number * @return next sequence number
*/ */
private def nextSequence: Int = { private def nextSequence: Int = {
if (outSequence >= 0xffff) { if (outSequence >= 0x8000) {
send(ResetSequence(), Some(outSequence), crypto)
performResetSequenceReset() performResetSequenceReset()
0 0
} else { } else {
@ -258,7 +259,6 @@ class MiddlewareActor(
* and gaslight the client to send packets using refreshed (delivered) id's. * and gaslight the client to send packets using refreshed (delivered) id's.
*/ */
private def performResetSequenceReset(): Unit = { private def performResetSequenceReset(): Unit = {
send(ResetSequence(), None, crypto)
outSequence = 0 outSequence = 0
inSequence = 0 inSequence = 0
} }

View file

@ -39,14 +39,12 @@ object PacketCoding {
): Attempt[BitVector] = { ): Attempt[BitVector] = {
packet match { packet match {
case _: PlanetSideControlPacket if crypto.isEmpty => case _: PlanetSideControlPacket if crypto.isEmpty =>
marshalPacketWithSequence(packet, BitVector.empty, crypto) marshalPacket(packet, BitVector.empty, crypto)
case _: PlanetSideResetSequencePacket =>
marshalPacketWithSequence(packet, BitVector.empty, crypto)
case _ => case _ =>
sequenceOpt match { sequenceOpt match {
case Some(sequence) => case Some(sequence) =>
uint16L.encode(sequence) match { uint16L.encode(sequence) match {
case Successful(encodedSequence) => marshalPacketWithSequence(packet, encodedSequence, crypto) case Successful(encodedSequence) => marshalPacket(packet, encodedSequence, crypto)
case f: Failure => f case f: Failure => f
} }
case None => case None =>
@ -55,6 +53,19 @@ object PacketCoding {
} }
} }
/** Common flags for normal encrypted packets. */
private val normalSecuredFlags: BitVector = PlanetSidePacketFlags.codec
.encode(PlanetSidePacketFlags(PacketType.Normal, secured = true))
.require
/** Common flags for normal unencrypted packets. */
private val normalNotSecuredFlags: BitVector = PlanetSidePacketFlags.codec
.encode(PlanetSidePacketFlags(PacketType.Normal, secured = false))
.require
/** Common flags for crypto unencrypted packets (that's not illogical). */
private val cryptoNotSecuredFlags: BitVector = PlanetSidePacketFlags.codec
.encode(PlanetSidePacketFlags(PacketType.Crypto, secured = false))
.require
/** /**
* Transform a kind of packet into the sequence of data that represents it. * Transform a kind of packet into the sequence of data that represents it.
* @param packet the packet to encode * @param packet the packet to encode
@ -62,27 +73,25 @@ object PacketCoding {
* @param crypto if set, encrypt final payload * @param crypto if set, encrypt final payload
* @return a `BitVector` translated from the packet's data * @return a `BitVector` translated from the packet's data
*/ */
private def marshalPacketWithSequence( private def marshalPacket(
packet: PlanetSidePacket, packet: PlanetSidePacket,
sequence: BitVector, sequence: BitVector,
crypto: Option[CryptoCoding] = None crypto: Option[CryptoCoding]
): Attempt[BitVector] = { ): Attempt[BitVector] = {
packet match { packet match {
case _: PlanetSideGamePacket | _: PlanetSideControlPacket if crypto.isDefined => case _: PlanetSideGamePacket | _: PlanetSideControlPacket if crypto.isDefined =>
encodePacket(packet) encodePacket(packet)
.flatMap { _payload => crypto.get.encrypt(_payload.bytes) } .flatMap { _payload => crypto.get.encrypt(_payload.bytes) }
.flatMap { encryptedPayload => .flatMap { encryptedPayload =>
// encrypted packets need to be aligned to 4 bytes before encryption/decryption // these encrypted packets need to be aligned to 4 bytes before encryption/decryption
// first byte are flags, second is the sequence, and third is the pad // first byte are flags, second is the sequence, and third is the pad
val flags = PlanetSidePacketFlags.codec.encode(PlanetSidePacketFlags(PacketType.Normal, secured = true)).require
val payload = hex"00".bits ++ encryptedPayload.bits val payload = hex"00".bits ++ encryptedPayload.bits
Successful(flags ++ sequence ++ payload) Successful(normalSecuredFlags ++ sequence ++ payload)
} }
case packet: PlanetSideGamePacket => case packet: PlanetSideGamePacket =>
encodePacket(packet) encodePacket(packet)
.flatMap { _payload => .flatMap { _payload =>
val flags = PlanetSidePacketFlags.codec.encode(PlanetSidePacketFlags(PacketType.Normal, secured = false)).require Successful(normalNotSecuredFlags ++ sequence ++ _payload)
Successful(flags ++ sequence ++ _payload)
} }
case packet: PlanetSideControlPacket => case packet: PlanetSideControlPacket =>
encodePacket(packet) encodePacket(packet)
@ -92,20 +101,18 @@ object PacketCoding {
case packet: PlanetSideCryptoPacket => case packet: PlanetSideCryptoPacket =>
encodePacket(packet) encodePacket(packet)
.flatMap { _payload => .flatMap { _payload =>
val flags = PlanetSidePacketFlags.codec.encode(PlanetSidePacketFlags(PacketType.Crypto, secured = false)).require Successful(cryptoNotSecuredFlags ++ sequence ++ _payload)
Successful(flags ++ sequence ++ _payload)
} }
case packet: PlanetSideResetSequencePacket if crypto.isDefined => case packet: PlanetSideResetSequencePacket if crypto.isDefined =>
encodePacket(packet) encodePacket(packet)
.flatMap { _payload => crypto.get.encrypt(_payload.bytes) } .flatMap { _payload => crypto.get.encrypt(_payload.bytes) }
.flatMap { encryptedPayload => .flatMap { encryptedPayload =>
//uncommon, so it's fine to not cache these flags (above)
val flags = PlanetSidePacketFlags.codec.encode(PlanetSidePacketFlags(PacketType.ResetSequence, secured = true)).require val flags = PlanetSidePacketFlags.codec.encode(PlanetSidePacketFlags(PacketType.ResetSequence, secured = true)).require
Successful(flags ++ sequence ++ encryptedPayload.bits) Successful(flags ++ sequence ++ encryptedPayload.bits)
} }
case _: PlanetSideResetSequencePacket =>
Failure(Err(s"can not marshal a ResetSequence packet when crypto state is unavailable"))
case _ => case _ =>
Failure(Err(s"can not marshal $packet")) Failure(Err(s"can not marshal $packet, sequence? $sequence, crypto state? ${crypto.isDefined}"))
} }
} }