diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 522a20da..a8a7f4d3 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -491,11 +491,11 @@ object GamePacketOpcode extends Enumeration { case 0x90 => noDecoder(OutfitMemberEvent) case 0x91 => noDecoder(OutfitMemberUpdate) case 0x92 => game.PlanetsideStringAttributeMessage.decode - case 0x93 => noDecoder(DataChallengeMessage) - case 0x94 => noDecoder(DataChallengeMessageResp) + case 0x93 => game.DataChallengeMessage.decode + case 0x94 => game.DataChallengeMessageResp.decode case 0x95 => game.WeatherMessage.decode - case 0x96 => noDecoder(SimDataChallenge) - case 0x97 => noDecoder(SimDataChallengeResp) + case 0x96 => game.SimDataChallenge.decode + case 0x97 => game.SimDataChallengeResp.decode // 0x98 case 0x98 => noDecoder(OutfitListEvent) case 0x99 => noDecoder(EmpireIncentivesMessage) diff --git a/common/src/main/scala/net/psforever/packet/game/DataChallenge.scala b/common/src/main/scala/net/psforever/packet/game/DataChallenge.scala new file mode 100644 index 00000000..7332fba5 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/DataChallenge.scala @@ -0,0 +1,9 @@ +// Copyright (c) 2020 PSForever +package net.psforever.packet.game + +import net.psforever.packet.PacketHelpers +import scodec.codecs.ulongL + +object DataChallenge { + val codec = PacketHelpers.encodedString :: ulongL(bits = 32) +} diff --git a/common/src/main/scala/net/psforever/packet/game/DataChallengeMessage.scala b/common/src/main/scala/net/psforever/packet/game/DataChallengeMessage.scala new file mode 100644 index 00000000..9ba4decf --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/DataChallengeMessage.scala @@ -0,0 +1,23 @@ +// Copyright (c) 2020 PSForever +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import scodec.{Attempt, Codec} +import scodec.bits.BitVector + +/** + * Our packet captures contain no examples of `DataChallengeMessage`. + * @param attribute na + * @param value na + */ +final case class DataChallengeMessage(attribute : String, + value : Long) + extends PlanetSideGamePacket { + type Packet = DataChallengeMessage + def opcode : GamePacketOpcode.Value = GamePacketOpcode.DataChallengeMessage + def encode : Attempt[BitVector] = DataChallengeMessage.encode(this) +} + +object DataChallengeMessage extends Marshallable[DataChallengeMessage] { + implicit val codec : Codec[DataChallengeMessage] = DataChallenge.codec.as[DataChallengeMessage] +} diff --git a/common/src/main/scala/net/psforever/packet/game/DataChallengeMessageResp.scala b/common/src/main/scala/net/psforever/packet/game/DataChallengeMessageResp.scala new file mode 100644 index 00000000..d4d1f80b --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/DataChallengeMessageResp.scala @@ -0,0 +1,23 @@ +// Copyright (c) 2020 PSForever +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import scodec.{Attempt, Codec} +import scodec.bits.BitVector + +/** + * Our packet captures contain no examples of `DataChallengeMessageResp`. + * @param attribute na + * @param value na + */ +final case class DataChallengeMessageResp(attribute : String, + value : Long) + extends PlanetSideGamePacket { + type Packet = DataChallengeMessageResp + def opcode : GamePacketOpcode.Value = GamePacketOpcode.DataChallengeMessageResp + def encode : Attempt[BitVector] = DataChallengeMessageResp.encode(this) +} + +object DataChallengeMessageResp extends Marshallable[DataChallengeMessageResp] { + implicit val codec : Codec[DataChallengeMessageResp] = DataChallenge.codec.as[DataChallengeMessageResp] +} diff --git a/common/src/main/scala/net/psforever/packet/game/SimDataChallenge.scala b/common/src/main/scala/net/psforever/packet/game/SimDataChallenge.scala new file mode 100644 index 00000000..e0e8c51e --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/SimDataChallenge.scala @@ -0,0 +1,36 @@ +// Copyright (c) 2020 PSForever +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import scodec.{Attempt, Codec} +import scodec.bits.BitVector +import scodec.codecs._ + +/** + * na + * @param unk1 na + * @param unk2 na + * @param unk3 na + * @param unk4 na + * @param unk5 na + */ +final case class SimDataChallenge(unk1 : List[Long], + unk2 : Boolean, + unk3 : Int, + unk4 : Long, + unk5 : Boolean) + extends PlanetSideGamePacket { + type Packet = SimDataChallenge + def opcode : GamePacketOpcode.Value = GamePacketOpcode.SimDataChallenge + def encode : Attempt[BitVector] = SimDataChallenge.encode(this) +} + +object SimDataChallenge extends Marshallable[SimDataChallenge] { + implicit val codec : Codec[SimDataChallenge] = ( + ("unk1" | listOfN(uint16L, ulongL(bits = 32))) :: + ("unk2" | bool) :: + ("unk3" | uint8) :: + ("unk4" | ulongL(bits = 32)) :: + ("unk5" | bool) + ).as[SimDataChallenge] +} diff --git a/common/src/main/scala/net/psforever/packet/game/SimDataChallengeResp.scala b/common/src/main/scala/net/psforever/packet/game/SimDataChallengeResp.scala new file mode 100644 index 00000000..14b64b9a --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/SimDataChallengeResp.scala @@ -0,0 +1,30 @@ +// Copyright (c) 2020 PSForever +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import scodec.{Attempt, Codec} +import scodec.bits.BitVector +import scodec.codecs._ + +/** + * na + * @param unk1 na + * @param unk2 na + * @param unk3 na + */ +final case class SimDataChallengeResp(unk1 : List[Long], + unk2 : List[Long], + unk3 : Boolean) + extends PlanetSideGamePacket { + type Packet = SimDataChallengeResp + def opcode : GamePacketOpcode.Value = GamePacketOpcode.SimDataChallengeResp + def encode : Attempt[BitVector] = SimDataChallengeResp.encode(this) +} + +object SimDataChallengeResp extends Marshallable[SimDataChallengeResp] { + implicit val codec : Codec[SimDataChallengeResp] = ( + ("unk1" | listOfN(uint16L, ulongL(bits = 32))) :: + ("unk2" | listOfN(uint16L, ulongL(bits = 32))) :: + ("unk3" | bool) + ).as[SimDataChallengeResp] +} diff --git a/common/src/test/scala/game/DataChallengeMessageRespTest.scala b/common/src/test/scala/game/DataChallengeMessageRespTest.scala new file mode 100644 index 00000000..51e002df --- /dev/null +++ b/common/src/test/scala/game/DataChallengeMessageRespTest.scala @@ -0,0 +1,28 @@ +// Copyright (c) 2020 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class DataChallengeMessageRespTest extends Specification { + val string = hex"948673616d706c6501000000" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case DataChallengeMessageResp(attribute, value) => + attribute mustEqual "sample" + value mustEqual 1L + case _ => + ko + } + } + + "encode" in { + val msg = DataChallengeMessageResp("sample", 1L) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} diff --git a/common/src/test/scala/game/DataChallengeMessageTest.scala b/common/src/test/scala/game/DataChallengeMessageTest.scala new file mode 100644 index 00000000..16fb41d4 --- /dev/null +++ b/common/src/test/scala/game/DataChallengeMessageTest.scala @@ -0,0 +1,28 @@ +// Copyright (c) 2020 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class DataChallengeMessageTest extends Specification { + val string = hex"938673616d706c6501000000" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case DataChallengeMessage(attribute, value) => + attribute mustEqual "sample" + value mustEqual 1L + case _ => + ko + } + } + + "encode" in { + val msg = DataChallengeMessage("sample", 1L) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} diff --git a/common/src/test/scala/game/SimDataChallengeRespTest.scala b/common/src/test/scala/game/SimDataChallengeRespTest.scala new file mode 100644 index 00000000..dc2d033c --- /dev/null +++ b/common/src/test/scala/game/SimDataChallengeRespTest.scala @@ -0,0 +1,33 @@ +// Copyright (c) 2020 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class SimDataChallengeRespTest extends Specification { + val string = hex"97050067030000e9030000e1040000000100006502000005003b3388faa52df48fb27971e7c3a9d0c109d5b03f00" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case SimDataChallengeResp(u1, u2, u3) => + u1 mustEqual List(871L, 1001L, 1249L, 256L, 613L) + u2 mustEqual List(4203230011L, 2415144357L, 3882973618L, 3251677635L, 1068553481L) + u3 mustEqual false + case _ => + ko + } + } + + "encode" in { + val msg = SimDataChallengeResp( + List(871L, 1001L, 1249L, 256L, 613L), + List(4203230011L, 2415144357L, 3882973618L, 3251677635L, 1068553481L), + false + ) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} diff --git a/common/src/test/scala/game/SimDataChallengeTest.scala b/common/src/test/scala/game/SimDataChallengeTest.scala new file mode 100644 index 00000000..90b068e4 --- /dev/null +++ b/common/src/test/scala/game/SimDataChallengeTest.scala @@ -0,0 +1,31 @@ +// Copyright (c) 2020 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class SimDataChallengeTest extends Specification { + val string = hex"96050067030000e9030000e10400000001000065020000808000000000" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case SimDataChallenge(u1, u2, u3, u4, u5) => + u1 mustEqual List(871L, 1001L, 1249L, 256L, 613L) + u2 mustEqual true + u3 mustEqual 1 + u4 mustEqual 0L + u5 mustEqual false + case _ => + ko + } + } + + "encode" in { + val msg = SimDataChallenge(List(871L, 1001L, 1249L, 256L, 613L), true, 1, 0, false) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +}