From 9703ac402d9f3e69a4d36a7c7fc5357c28cbc96d Mon Sep 17 00:00:00 2001 From: Resaec Date: Wed, 27 Dec 2023 06:25:40 +0100 Subject: [PATCH] OutfitMembershipRequest packet start --- .../psforever/packet/GamePacketOpcode.scala | 2 +- .../packet/game/OutfitMembershipRequest.scala | 102 +++++++++ .../game/OutfitMembershipRequestTest.scala | 200 ++++++++++++++++++ 3 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/net/psforever/packet/game/OutfitMembershipRequest.scala create mode 100644 src/test/scala/game/OutfitMembershipRequestTest.scala diff --git a/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 3fcd0449..a2beebc0 100644 --- a/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -468,7 +468,7 @@ object GamePacketOpcode extends Enumeration { case 0x89 => game.BugReportMessage.decode case 0x8a => game.PlayerStasisMessage.decode case 0x8b => noDecoder(UnknownMessage139) - case 0x8c => noDecoder(OutfitMembershipRequest) + case 0x8c => game.OutfitMembershipRequest.decode case 0x8d => noDecoder(OutfitMembershipResponse) case 0x8e => game.OutfitRequest.decode case 0x8f => noDecoder(OutfitEvent) diff --git a/src/main/scala/net/psforever/packet/game/OutfitMembershipRequest.scala b/src/main/scala/net/psforever/packet/game/OutfitMembershipRequest.scala new file mode 100644 index 00000000..a6e6bded --- /dev/null +++ b/src/main/scala/net/psforever/packet/game/OutfitMembershipRequest.scala @@ -0,0 +1,102 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} +import net.psforever.types.PlanetSideGUID +import scodec.Codec +import scodec.codecs._ + +final case class OutfitMembershipRequest( + request_type: OutfitMembershipRequest.RequestType.Type, + avatar_guid: PlanetSideGUID, + unk1: Int, + unk2: String, + unk3: Int, + unk4: Boolean, + outfit_name: String +) extends PlanetSideGamePacket { + type Packet = OutfitMembershipRequest + + def opcode = GamePacketOpcode.OutfitMembershipRequest + + def encode = OutfitMembershipRequest.encode(this) +} + +object OutfitMembershipRequest extends Marshallable[OutfitMembershipRequest] { + + object RequestType extends Enumeration { + type Type = Value + + val Create = Value(0x0) + val Form = Value(0x1) + val Accept = Value(0x3) + val Reject = Value(0x4) + val Cancel = Value(0x5) + + implicit val codec: Codec[Type] = PacketHelpers.createEnumerationCodec(this, uintL(3)) + } + + implicit val codec: Codec[OutfitMembershipRequest] = ( + ("request_type" | RequestType.codec) :: + ("avatar_guid" | PlanetSideGUID.codec) :: // as in DB avatar table + ("unk1" | uint16L) :: // avatar2_guid / invited player ? + ("unk2" | PacketHelpers.encodedWideString) :: // could be string + ("unk3" | uint4L) :: + ("unk4" | bool) :: + ("outfit_name" | PacketHelpers.encodedWideString) + ).as[OutfitMembershipRequest] +} + +/* + +/outfitcreate + +0 0200 000 1000 83 410042004300 -- /outfitcreate ABC -- from AA - TR BR 24 CR 0 +0 0200 000 1000 83 410042004300 -- /outfitcreate ABC -- from AA - TR BR 24 CR 0 +0 1000 000 1000 83 410042004300 -- /outfitcreate ABC -- from TTEESSTT - TR BR 24 CR 0 + +0 0a00 000 1000 83 310032003300 -- /outfitcreate 123 -- from BBBB - TR BR 1 CR 0 +0 0a00 000 1000 83 310032003300 +0 0a00 000 1000 83 310032003300 +0 0a00 000 1000 83 310032003300 +0 0a00 000 1000 83 410042004300 -- ABC + +0 0400 000 1000 83 580059005a00 -- /outfitcreate XYZ -- from BB - VS BR 24 CR 0 + +0 1000 000 1000 84 3200320032003200 -- /outfitcreate 2222 -- from TTEESSTT - TR BR 24 CR 0 + +/outfitform + +20 2000 00 1000 83 610062006300 -- /outfitform abc -- from AA - TR BR 24 CR 0 +21 0000 00 1000 81 3100 -- /outfitform 1 -- from TTEESSTT - TR BR 24 CR 0 + +/outfitinvite + +3 // guess + +/outfitkick + +4 // guess + +/outfitaccept + +60 2000 00 1000 -- from AA - TR BR 24 CR 0 +60 4000 00 1000 -- from BB - VS BR 24 CR 0 + +/outfitreject + +80 2000 00 1000 -- from AA - TR BR 24 CR 0 +80 4000 00 1000 -- from BB - VS BR 24 CR 0 +80 6000 00 1000 -- from BBB - NC BR 1 CR 0 + +/outfitcancel + +a0 2000 00 0000 0000 1000 -- from AA - TR BR 24 CR 0 +a0 4000 00 0000 0000 1000 -- from BB - VS BR 24 CR 0 +a0 6000 00 0000 0000 1000 -- from BBB - NC BR 1 CR 0 + +a0 2000 00 0000 0000 1060 610064006200 -- /outfitcancel abc -- from AA - TR BR 24 CR 0 +a0 2000 00 0000 0000 1080 3100320033003400 -- /outfitcancel 1234 -- from AA - TR BR 24 CR 0 + + */ + diff --git a/src/test/scala/game/OutfitMembershipRequestTest.scala b/src/test/scala/game/OutfitMembershipRequestTest.scala new file mode 100644 index 00000000..4ef80419 --- /dev/null +++ b/src/test/scala/game/OutfitMembershipRequestTest.scala @@ -0,0 +1,200 @@ +// Copyright (c) 2017 PSForever +package game + +import net.psforever.packet._ +import net.psforever.packet.game.OutfitMembershipRequest.RequestType +import net.psforever.packet.game._ +import net.psforever.types.PlanetSideGUID +import org.specs2.mutable._ +import scodec.bits._ + +class OutfitMembershipRequestTest extends Specification { + val create_ABC = hex"8c 0 0200 000 1000 83 410042004300" + val create_2222 = hex"8c 0 1000 000 1000 84 3200320032003200" + val form_abc = hex"8c 2 0200 000 1000 83 610062006300" + val form_1 = hex"8c 2 1000 000 1000 81 3100" + val accept_1 = hex"8c 6 0200 000 1000" + val accept_2 = hex"8c 6 0400 000 1000" + val reject_1 = hex"8c 8 0200 000 1000" + val reject_2 = hex"8c 8 0400 000 1000" + val cancel_5 = hex"8c a 0600 000 0000 0000 1000" + val cancel_1_abc = hex"8c a 0200 000 0000 0000 1060 610064006200" + + "decode create ABC" in { + PacketCoding.decodePacket(create_ABC).require match { + case OutfitMembershipRequest(request_type, avatar_id, unk1, unk2, unk3, unk4, outfit_name) => + request_type mustEqual RequestType.Create + avatar_id mustEqual 1 + unk1 mustEqual 0 + unk2 mustEqual "" + unk3 mustEqual 0 + unk4 mustEqual false + outfit_name mustEqual "ABC" + case _ => + ko + } + } + + "encode create ABC" in { + val msg = OutfitMembershipRequest(RequestType.Create, PlanetSideGUID(1), 0, "", 0, unk4 = false, "ABC") + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual create_ABC + } + + "decode create 2222" in { + PacketCoding.decodePacket(create_2222).require match { + case OutfitMembershipRequest(request_type, avatar_id, unk1, unk2, unk3, unk4, outfit_name) => + request_type mustEqual RequestType.Create + avatar_id mustEqual PlanetSideGUID(8) + unk1 mustEqual 0 + unk2 mustEqual "" + unk3 mustEqual 0 + unk4 mustEqual false + outfit_name mustEqual "2222" + case _ => + ko + } + } + + "encode create 2222" in { + val msg = OutfitMembershipRequest(RequestType.Create, PlanetSideGUID(8), 0, "", 0, unk4 = false, "2222") + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual create_2222 + } + + "decode form abc" in { + PacketCoding.decodePacket(form_abc).require match { + case OutfitMembershipRequest(request_type, avatar_id, unk1, unk2, unk3, unk4, outfit_name) => + request_type mustEqual RequestType.Form + avatar_id mustEqual PlanetSideGUID(1) + unk1 mustEqual 0 + unk2 mustEqual "" + unk3 mustEqual 0 + unk4 mustEqual false + outfit_name mustEqual "abc" + case _ => + ko + } + } + + "encode form abc" in { + val msg = OutfitMembershipRequest(RequestType.Form, PlanetSideGUID(1), 0, "", 0, unk4 = false, "abc") + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual form_abc + } + + "decode form 1" in { + PacketCoding.decodePacket(form_1).require match { + case OutfitMembershipRequest(request_type, avatar_id, unk1, unk2, unk3, unk4, outfit_name) => + request_type mustEqual RequestType.Form + avatar_id mustEqual PlanetSideGUID(8) + unk1 mustEqual 0 + unk2 mustEqual "" + unk3 mustEqual 0 + unk4 mustEqual false + outfit_name mustEqual "1" + case _ => + ko + } + } + + "encode form 1" in { + val msg = OutfitMembershipRequest(RequestType.Form, PlanetSideGUID(8), 0, "", 0, unk4 = false, "1") + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual form_1 + } + + "decode accept 1" in { + PacketCoding.decodePacket(accept_1).require match { + case OutfitMembershipRequest(request_type, avatar_id, unk1, unk2, unk3, unk4, outfit_name) => + request_type mustEqual RequestType.Accept + avatar_id mustEqual PlanetSideGUID(1) + unk1 mustEqual 0 + unk2 mustEqual "" + unk3 mustEqual 0 + unk4 mustEqual false + outfit_name mustEqual "" + case _ => + ko + } + } + + "decode accept 2" in { + PacketCoding.decodePacket(accept_2).require match { + case OutfitMembershipRequest(request_type, avatar_id, unk1, unk2, unk3, unk4, outfit_name) => + request_type mustEqual RequestType.Accept + avatar_id mustEqual 2 + unk1 mustEqual 0 + unk2 mustEqual "" + unk3 mustEqual 0 + unk4 mustEqual false + outfit_name mustEqual "" + case _ => + ko + } + } + + "decode reject 1" in { + PacketCoding.decodePacket(reject_1).require match { + case OutfitMembershipRequest(request_type, avatar_id, unk1, unk2, unk3, unk4, outfit_name) => + request_type mustEqual RequestType.Reject + avatar_id mustEqual 1 + unk1 mustEqual 0 + unk2 mustEqual "" + unk3 mustEqual 0 + unk4 mustEqual false + outfit_name mustEqual "" + case _ => + ko + } + } + + "decode reject 2" in { + PacketCoding.decodePacket(reject_2).require match { + case OutfitMembershipRequest(request_type, avatar_id, unk1, unk2, unk3, unk4, outfit_name) => + request_type mustEqual RequestType.Reject + avatar_id mustEqual 2 + unk1 mustEqual 0 + unk2 mustEqual "" + unk3 mustEqual 0 + unk4 mustEqual false + outfit_name mustEqual "" + case _ => + ko + } + } + + "decode cancel 5" in { + PacketCoding.decodePacket(cancel_5).require match { + case OutfitMembershipRequest(request_type, avatar_id, unk1, unk2, unk3, unk4, outfit_name) => + request_type mustEqual RequestType.Cancel + avatar_id mustEqual 5 + unk1 mustEqual 0 + unk2 mustEqual "" + unk3 mustEqual 0 + unk4 mustEqual false + outfit_name mustEqual "" + case _ => + ko + } + } + + "decode reject 1 abc" in { + PacketCoding.decodePacket(cancel_1_abc).require match { + case OutfitMembershipRequest(request_type, avatar_id, unk1, unk2, unk3, unk4, outfit_name) => + request_type mustEqual RequestType.Cancel + avatar_id mustEqual 1 + unk1 mustEqual 0 + unk2 mustEqual "" + unk3 mustEqual 0 + unk4 mustEqual false + outfit_name mustEqual "abc" + case _ => + ko + } + } +}