diff --git a/src/main/scala/net/psforever/packet/game/OutfitEvent.scala b/src/main/scala/net/psforever/packet/game/OutfitEvent.scala index 798502378..1a633fa2c 100644 --- a/src/main/scala/net/psforever/packet/game/OutfitEvent.scala +++ b/src/main/scala/net/psforever/packet/game/OutfitEvent.scala @@ -3,7 +3,6 @@ package net.psforever.packet.game import net.psforever.packet.GamePacketOpcode.Type import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} -import net.psforever.types.PlanetSideGUID import scodec.{Attempt, Codec, Err} import scodec.bits.BitVector import scodec.codecs._ diff --git a/src/main/scala/net/psforever/packet/game/OutfitMemberEvent.scala b/src/main/scala/net/psforever/packet/game/OutfitMemberEvent.scala index 67c95820c..0a0f31f25 100644 --- a/src/main/scala/net/psforever/packet/game/OutfitMemberEvent.scala +++ b/src/main/scala/net/psforever/packet/game/OutfitMemberEvent.scala @@ -3,42 +3,52 @@ package net.psforever.packet.game import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} import scodec.Codec +import scodec.bits.ByteVector import scodec.codecs._ import shapeless.{::, HNil} +/* + action is unimplemented! if action == 0 only outfit_id and member_id are sent + action2 is unimplemented! if action2 == 0 unk2 will contain one additional uint32L + unk2 contains one byte of padding. may contain 4byte of unknown data depending on action2 + */ final case class OutfitMemberEvent( - unk00: Int, - outfit_id: Long, - member_id: Long, - member_name: String, - rank: Int, // 0-7 - points: Long, // client divides this by 100 - last_login: Long, // seconds ago from current time, 0 if online - unk1: Int, -) extends PlanetSideGamePacket { + action: Int, // action is unimplemented + outfit_id: Long, + member_id: Long, + member_name: String, + rank: Int, // 0-7 + points: Long, // client divides this by 100 + last_login: Long, // seconds ago from current time, 0 if online + action2: Int, // this should always be 1, otherwise there will be actual data in unk2! + padding: ByteVector, // only contains information if unk1 is 0, 1 byte of padding otherwise + ) extends PlanetSideGamePacket { type Packet = OutfitMemberEvent + def opcode = GamePacketOpcode.OutfitMemberEvent + def encode = OutfitMemberEvent.encode(this) } object OutfitMemberEvent extends Marshallable[OutfitMemberEvent] { implicit val codec: Codec[OutfitMemberEvent] = ( - ("unk00" | uintL(2)) :: - ("outfit_id" | uint32L) :: - ("member_id" | uint32L) :: - ("member_name" | PacketHelpers.encodedWideStringAligned(6)) :: - ("rank" | uint(3)) :: - ("points" | uint32L) :: - ("last_login" | uint32L) :: - ("unk1" | uint(5)) + ("action" | uintL(2)) :: + ("outfit_id" | uint32L) :: + ("member_id" | uint32L) :: + ("member_name" | PacketHelpers.encodedWideStringAligned(6)) :: + ("rank" | uint(3)) :: + ("points" | uint32L) :: + ("last_login" | uint32L) :: + ("action2" | uintL(1)) :: + ("padding" | bytes) ).xmap[OutfitMemberEvent]( { - case unk00 :: outfit_id :: member_id :: member_name :: rank :: points :: last_login :: u1 :: HNil => - OutfitMemberEvent(unk00, outfit_id, member_id, member_name, rank, points, last_login, u1) + case unk00 :: outfit_id :: member_id :: member_name :: rank :: points :: last_login :: u1 :: padding :: HNil => + OutfitMemberEvent(unk00, outfit_id, member_id, member_name, rank, points, last_login, u1, padding) }, { - case OutfitMemberEvent(unk00, outfit_id, member_id, member_name, rank, points, last_login, u1) => - unk00 :: outfit_id :: member_id :: member_name :: rank :: points :: last_login :: u1 :: HNil + case OutfitMemberEvent(unk00, outfit_id, member_id, member_name, rank, points, last_login, action2, padding) => + unk00 :: outfit_id :: member_id :: member_name :: rank :: points :: last_login :: action2 :: padding :: HNil } ) } diff --git a/src/main/scala/net/psforever/packet/game/OutfitMemberUpdate.scala b/src/main/scala/net/psforever/packet/game/OutfitMemberUpdate.scala index 39f682964..88cae6328 100644 --- a/src/main/scala/net/psforever/packet/game/OutfitMemberUpdate.scala +++ b/src/main/scala/net/psforever/packet/game/OutfitMemberUpdate.scala @@ -2,7 +2,6 @@ package net.psforever.packet.game import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} -import net.psforever.types.PlanetSideGUID import scodec.Codec import scodec.codecs._ import shapeless.{::, HNil} diff --git a/src/main/scala/net/psforever/packet/game/OutfitMembershipRequest.scala b/src/main/scala/net/psforever/packet/game/OutfitMembershipRequest.scala index 6d3c17ea0..5e0c8b9b7 100644 --- a/src/main/scala/net/psforever/packet/game/OutfitMembershipRequest.scala +++ b/src/main/scala/net/psforever/packet/game/OutfitMembershipRequest.scala @@ -22,41 +22,50 @@ final case class OutfitMembershipRequest( abstract class OutfitMembershipRequestAction(val code: Int) +/* + Codecs 2,5,6,7 can either work off of the avatar_id (if GUI was used) or member_name (if chat command was used) + */ object OutfitMembershipRequestAction { - final case class CreateOutfit( - unk2: String, - unk3: Int, - unk4: Boolean, + final case class Create( + unk1: String, outfit_name: String ) extends OutfitMembershipRequestAction(code = 0) - final case class FormOutfit( - unk2: String, - unk3: Int, - unk4: Boolean, + final case class Form( + unk1: String, outfit_name: String ) extends OutfitMembershipRequestAction(code = 1) - final case class Unk2( - unk2: Int, - unk3: Int, + final case class Invite( + avatar_id: Long, member_name: String, ) extends OutfitMembershipRequestAction(code = 2) - final case class AcceptOutfitInvite( - unk2: String + + final case class AcceptInvite( + member_name: String ) extends OutfitMembershipRequestAction(code = 3) - final case class RejectOutfitInvite( - unk2: String + final case class RejectInvite( + member_name: String ) extends OutfitMembershipRequestAction(code = 4) - final case class CancelOutfitInvite( - unk5: Int, - unk6: Int, - outfit_name: String + final case class CancelInvite( + avatar_id: Long, + member_name: String, ) extends OutfitMembershipRequestAction(code = 5) + final case class Kick( + avatar_id: Long, + member_name: String, + ) extends OutfitMembershipRequestAction(code = 6) + + final case class SetRank( + avatar_id: Long, // 32 + rank: Int, // 3 + member_name: String, + ) extends OutfitMembershipRequestAction(code = 7) + final case class Unknown(badCode: Int, data: BitVector) extends OutfitMembershipRequestAction(badCode) /** @@ -66,96 +75,122 @@ object OutfitMembershipRequestAction { object Codecs { private val everFailCondition = conditional(included = false, bool) - val CreateOutfitCodec: Codec[CreateOutfit] = + val CreateCodec: Codec[Create] = ( - PacketHelpers.encodedWideString :: - uint4L :: - bool :: + PacketHelpers.encodedWideStringAligned(5) :: PacketHelpers.encodedWideString - ).xmap[CreateOutfit]( + ).xmap[Create]( { - case unk2 :: unk3 :: unk4 :: outfit_name :: HNil => - CreateOutfit(unk2, unk3, unk4, outfit_name) + case u1 :: outfit_name :: HNil => + Create(u1, outfit_name) }, { - case CreateOutfit(unk2, unk3, unk4, outfit_name) => - unk2 :: unk3 :: unk4 :: outfit_name :: HNil + case Create(u1, outfit_name) => + u1 :: outfit_name :: HNil } ) - val FormOutfitCodec: Codec[FormOutfit] = + val FormCodec: Codec[Form] = ( - PacketHelpers.encodedWideString :: - uint4L :: - bool :: + PacketHelpers.encodedWideStringAligned(5) :: PacketHelpers.encodedWideString - ).xmap[FormOutfit]( + ).xmap[Form]( { - case unk2 :: unk3 :: unk4 :: outfit_name :: HNil => - FormOutfit(unk2, unk3, unk4, outfit_name) + case u1 :: outfit_name :: HNil => + Form(u1, outfit_name) }, { - case FormOutfit(unk2, unk3, unk4, outfit_name) => - unk2 :: unk3 :: unk4 :: outfit_name :: HNil + case Form(u1, outfit_name) => + u1 :: outfit_name :: HNil } ) - val Unk2Codec: Codec[Unk2] = + val InviteCodec: Codec[Invite] = ( - uint16L :: - uint16L :: + uint32L :: PacketHelpers.encodedWideStringAligned(5) - ).xmap[Unk2]( + ).xmap[Invite]( { - case unk2 :: unk3 :: member_name :: HNil => - Unk2(unk2, unk3, member_name) + case u1 :: member_name :: HNil => + Invite(u1, member_name) }, { - case Unk2(unk2, unk3, member_name) => - unk2 :: unk3 :: member_name :: HNil + case Invite(u1, member_name) => + u1 :: member_name :: HNil } ) - val AcceptOutfitCodec: Codec[AcceptOutfitInvite] = - PacketHelpers.encodedWideString.xmap[AcceptOutfitInvite]( + val AcceptInviteCodec: Codec[AcceptInvite] = + PacketHelpers.encodedWideString.xmap[AcceptInvite]( { - case unk2 => - AcceptOutfitInvite(unk2) + case u1 => + AcceptInvite(u1) }, { - case AcceptOutfitInvite(unk2) => - unk2 + case AcceptInvite(u1) => + u1 } ) - val RejectOutfitCodec: Codec[RejectOutfitInvite] = - PacketHelpers.encodedWideString.xmap[RejectOutfitInvite]( + val RejectInviteCodec: Codec[RejectInvite] = + PacketHelpers.encodedWideString.xmap[RejectInvite]( { - case unk2 => - RejectOutfitInvite(unk2) + case u1 => + RejectInvite(u1) }, { - case RejectOutfitInvite(unk2) => - unk2 + case RejectInvite(u1) => + u1 } ) - val CancelOutfitCodec: Codec[CancelOutfitInvite] = + val CancelInviteCodec: Codec[CancelInvite] = ( - uint16L :: - uint16L :: + uint32L :: PacketHelpers.encodedWideStringAligned(5) - ).xmap[CancelOutfitInvite]( + ).xmap[CancelInvite]( { - case unk5 :: unk6 :: outfit_name :: HNil => - CancelOutfitInvite(unk5, unk6, outfit_name) + case u1 :: outfit_name :: HNil => + CancelInvite(u1, outfit_name) }, { - case CancelOutfitInvite(unk5, unk6, outfit_name) => - unk5 :: unk6 :: outfit_name :: HNil + case CancelInvite(u1, outfit_name) => + u1 :: outfit_name :: HNil } ) + val KickCodec: Codec[Kick] = + ( + uint32L :: + PacketHelpers.encodedWideStringAligned(5) + ).xmap[Kick]( + { + case u1 :: member_name :: HNil => + Kick(u1, member_name) + }, + { + case Kick(u1, member_name) => + u1 :: member_name :: HNil + } + ) + + val SetRankCodec: Codec[SetRank] = + ( + uint32L :: + uintL(3) :: + PacketHelpers.encodedWideStringAligned(2) + ).xmap[SetRank]( + { + case u1 :: rank :: member_name :: HNil => + SetRank(u1, rank, member_name) + }, + { + case SetRank(u1, rank, member_name) => + u1 :: rank :: member_name :: HNil + } + ) + + /** * A common form for known action code indexes with an unknown purpose and transformation is an "Unknown" object. * @@ -191,12 +226,12 @@ object OutfitMembershipRequest extends Marshallable[OutfitMembershipRequest] { val Create: RequestType.Value = Value(0) val Form: RequestType.Value = Value(1) - val Unk2: RequestType.Value = Value(2) + val Invite: RequestType.Value = Value(2) val Accept: RequestType.Value = Value(3) val Reject: RequestType.Value = Value(4) val Cancel: RequestType.Value = Value(5) - val Unk6: RequestType.Value = Value(6) // 6 and 7 seen as failed decodes, validity unknown - val Unk7: RequestType.Value = Value(7) + val Kick: RequestType.Value = Value(6) + val SetRank: RequestType.Value = Value(7) implicit val codec: Codec[Type] = PacketHelpers.createEnumerationCodec(this, uintL(3)) } @@ -206,15 +241,15 @@ object OutfitMembershipRequest extends Marshallable[OutfitMembershipRequest] { import scala.annotation.switch ((code: @switch) match { - case 0 => CreateOutfitCodec - case 1 => FormOutfitCodec // so far same as Create - case 2 => Unk2Codec - case 3 => AcceptOutfitCodec - case 4 => RejectOutfitCodec // so far same as Accept - case 5 => CancelOutfitCodec - case 6 => unknownCodec(action = code) - case 7 => unknownCodec(action = code) - // 3 bit limit + case 0 => CreateCodec + case 1 => FormCodec // so far same as Create + case 2 => InviteCodec + case 3 => AcceptInviteCodec + case 4 => RejectInviteCodec + case 5 => CancelInviteCodec + case 6 => KickCodec + case 7 => SetRankCodec + case _ => failureCodec(code) }).asInstanceOf[Codec[OutfitMembershipRequestAction]] } diff --git a/src/main/scala/net/psforever/packet/game/OutfitMembershipResponse.scala b/src/main/scala/net/psforever/packet/game/OutfitMembershipResponse.scala index 086d42eda..5b2aec24f 100644 --- a/src/main/scala/net/psforever/packet/game/OutfitMembershipResponse.scala +++ b/src/main/scala/net/psforever/packet/game/OutfitMembershipResponse.scala @@ -3,7 +3,6 @@ package net.psforever.packet.game import net.psforever.packet.GamePacketOpcode.Type import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} -import net.psforever.types.PlanetSideGUID import scodec.{Attempt, Codec, Err} import scodec.bits.BitVector import scodec.codecs._ @@ -12,10 +11,9 @@ import shapeless.{::, HNil} final case class OutfitMembershipResponse( response_type: OutfitMembershipResponse.ResponseType.Type, unk0: Int, + unk1: Int, outfit_id: Long, - target_guid: PlanetSideGUID, - unk3: Int, - //unk4: Boolean, + target_id: Long, action: OutfitMembershipResponseAction ) extends PlanetSideGamePacket { type Packet = OutfitMembershipResponse @@ -28,21 +26,39 @@ final case class OutfitMembershipResponse( abstract class OutfitMembershipResponseAction(val code: Int) object OutfitMembershipResponseAction { - final case class CreateOutfitResponse(str1: String, str2: String, str3: String) extends OutfitMembershipResponseAction(code = 0) + final case class Universal( + str1: String, + str2: String, + flag: Boolean + ) extends OutfitMembershipResponseAction(-1) - final case class Unk1OutfitResponse(player_name: String, outfit_name: String, unk7: Int) extends OutfitMembershipResponseAction(code = 1) + final case class CreateResponse( + str1: String, + str2: String, + str3: String + ) extends OutfitMembershipResponseAction(code = 0) - final case class Unk2OutfitResponse(player_name: String, outfit_name: String, unk7: Int) extends OutfitMembershipResponseAction(code = 2) // unk7 = rank? + final case class Unk1OutfitResponse( + player_name: String, + outfit_name: String, + unk7: Int + ) extends OutfitMembershipResponseAction(code = 1) - final case class Unk3OutfitResponse(unk2: String) extends OutfitMembershipResponseAction(code = 3) + final case class Unk2OutfitResponse( + player_name: String, + outfit_name: String, + unk7: Int + ) extends OutfitMembershipResponseAction(code = 2) // unk7 = rank? - final case class Unk4OutfitResponse(unk5: Int, unk6: Int, outfit_name: String) extends OutfitMembershipResponseAction(code = 4) + final case class Unk3OutfitResponse( + unk2: String + ) extends OutfitMembershipResponseAction(code = 3) - final case class Unk5OutfitResponse() extends OutfitMembershipResponseAction(code = 5) - - final case class Unk6OutfitResponse() extends OutfitMembershipResponseAction(code = 6) - - final case class Unk7OutfitResponse() extends OutfitMembershipResponseAction(code = 7) + final case class Unk4OutfitResponse( + unk5: Int, + unk6: Int, + outfit_name: String + ) extends OutfitMembershipResponseAction(code = 4) final case class Unknown(badCode: Int, data: BitVector) extends OutfitMembershipResponseAction(badCode) @@ -53,17 +69,32 @@ object OutfitMembershipResponseAction { object Codecs { private val everFailCondition = conditional(included = false, bool) - val Unk0OutfitCodec: Codec[CreateOutfitResponse] = ( + val UniversalResponseCodec: Codec[OutfitMembershipResponseAction] = ( + PacketHelpers.encodedWideStringAligned(5) :: + PacketHelpers.encodedWideString :: + ("flag" | bool) + ).xmap[OutfitMembershipResponseAction]( + { + case str1 :: str2 :: flag :: HNil => + Universal(str1, str2, flag) + }, + { + case Universal(str1, str2, flag) => + str1 :: str2 :: flag :: HNil + } + ) + + val CreateOutfitCodec: Codec[CreateResponse] = ( PacketHelpers.encodedWideStringAligned(5) :: PacketHelpers.encodedWideString :: PacketHelpers.encodedWideString - ).xmap[CreateOutfitResponse]( + ).xmap[CreateResponse]( { case str1 :: str2 :: str3 :: HNil => - CreateOutfitResponse(str1, str2, str3) + CreateResponse(str1, str2, str3) }, { - case CreateOutfitResponse(str1, str2, str3) => + case CreateResponse(str1, str2, str3) => str1 :: str2 :: str3 :: HNil } ) @@ -99,7 +130,7 @@ object OutfitMembershipResponseAction { ) val Unk3OutfitCodec: Codec[Unk3OutfitResponse] = - PacketHelpers.encodedWideString.xmap[Unk3OutfitResponse]( + PacketHelpers.encodedWideStringAligned(5).xmap[Unk3OutfitResponse]( { case unk2 => Unk3OutfitResponse(unk2) @@ -110,8 +141,11 @@ object OutfitMembershipResponseAction { } ) - val Unk4OutfitCodec: Codec[Unk4OutfitResponse] = - (uint16L :: uint16L :: PacketHelpers.encodedWideStringAligned(5)).xmap[Unk4OutfitResponse]( + val Unk4OutfitCodec: Codec[Unk4OutfitResponse] = ( + uint16L :: + uint16L :: + PacketHelpers.encodedWideStringAligned(5) + ).xmap[Unk4OutfitResponse]( { case unk5 :: unk6 :: outfit_name :: HNil => Unk4OutfitResponse(unk5, unk6, outfit_name) @@ -122,42 +156,6 @@ object OutfitMembershipResponseAction { } ) -// val Unk5OutfitCodec: Codec[Unk5OutfitResponse] = -// (uint16L :: uint16L :: PacketHelpers.encodedWideStringAligned(5)).xmap[Unk5OutfitResponse]( -// { -// case unk5 :: unk6 :: outfit_name :: HNil => -// Unk5OutfitResponse(unk5, unk6, outfit_name) -// }, -// { -// case Unk5OutfitResponse(unk5, unk6, outfit_name) => -// unk5 :: unk6 :: outfit_name :: HNil -// } -// ) -// -// val Unk6OutfitCodec: Codec[Unk6OutfitResponse] = -// (uint16L :: uint16L :: PacketHelpers.encodedWideStringAligned(5)).xmap[Unk6OutfitResponse]( -// { -// case _ => -// Unk6OutfitResponse() -// }, -// { -// case Unk6OutfitResponse() => -// _ -// } -// ) -// -// val Unk7OutfitCodec: Codec[Unk7OutfitResponse] = -// (uint16L :: uint16L :: PacketHelpers.encodedWideStringAligned(5)).xmap[Unk7OutfitResponse]( -// { -// case _ => -// Unk7OutfitResponse() -// }, -// { -// case Unk7OutfitResponse() => -// _ -// } -// ) - /** * A common form for known action code indexes with an unknown purpose and transformation is an "Unknown" object. * @param action the action behavior code @@ -206,14 +204,24 @@ object OutfitMembershipResponse extends Marshallable[OutfitMembershipResponse] { import scala.annotation.switch ((code: @switch) match { - case 0 => Unk0OutfitCodec // seem as OMReq Create response - case 1 => Unk1OutfitCodec - case 2 => Unk2OutfitCodec - case 3 => Unk3OutfitCodec - case 4 => Unk4OutfitCodec - case 5 => unknownCodec(action = code) - case 6 => unknownCodec(action = code) - case 7 => unknownCodec(action = code) + case 0 => UniversalResponseCodec + case 1 => UniversalResponseCodec + case 2 => UniversalResponseCodec + case 3 => UniversalResponseCodec + case 4 => UniversalResponseCodec + case 5 => UniversalResponseCodec + case 6 => UniversalResponseCodec + case 7 => UniversalResponseCodec + +// case 0 => CreateOutfitCodec // seem as OMReq Create response +// case 1 => Unk1OutfitCodec +// case 2 => Unk2OutfitCodec +// case 3 => Unk3OutfitCodec +// case 4 => Unk4OutfitCodec +// case 5 => unknownCodec(action = code) +// case 6 => unknownCodec(action = code) +// case 7 => unknownCodec(action = code) + // 3 bit limit case _ => failureCodec(code) }).asInstanceOf[Codec[OutfitMembershipResponseAction]] @@ -221,21 +229,20 @@ object OutfitMembershipResponse extends Marshallable[OutfitMembershipResponse] { implicit val codec: Codec[OutfitMembershipResponse] = ( ("response_type" | ResponseType.codec) >>:~ { response_type => - ("unk0" | uint8L) :: + ("unk0" | uintL(5)) :: + ("unk1" | uintL(3)) :: ("outfit_id" | uint32L) :: - ("target_guid" | PlanetSideGUID.codec) :: - ("unk3" | uint16L) :: - //("unk4" | bool) :: - ("action" | selectFromType(response_type.id)) + ("target_id" | uint32L) :: + ("action" | selectFromType(response_type.id)) } ).xmap[OutfitMembershipResponse]( { - case response_type :: u0 :: outfit_id :: target_guid :: u3 :: action :: HNil => - OutfitMembershipResponse(response_type, u0, outfit_id, target_guid, u3, action) + case response_type :: u0 :: u1 :: outfit_id :: target_id :: action :: HNil => + OutfitMembershipResponse(response_type, u0, u1, outfit_id, target_id, action) }, { - case OutfitMembershipResponse(response_type, u0, outfit_id, u2, u3, action) => - response_type :: u0 :: outfit_id :: u2 :: u3 :: action :: HNil + case OutfitMembershipResponse(response_type, u0, u1, outfit_id, target_id, action) => + response_type :: u0 :: u1 :: outfit_id :: target_id :: action :: HNil } ) } diff --git a/src/test/scala/game/OutfitEventTest.scala b/src/test/scala/game/OutfitEventTest.scala index 8837b93c1..e4a86cec8 100644 --- a/src/test/scala/game/OutfitEventTest.scala +++ b/src/test/scala/game/OutfitEventTest.scala @@ -5,7 +5,6 @@ import net.psforever.packet._ import net.psforever.packet.game.OutfitEvent.RequestType import net.psforever.packet.game.OutfitEventAction._ import net.psforever.packet.game._ -import net.psforever.types.PlanetSideGUID import org.specs2.mutable._ import scodec.bits._ @@ -64,7 +63,9 @@ class OutfitEventTest extends Specification { unk9 = 0, OutfitRankNames("Dog Meat","Russian","","","Squad Leaders","Acting Commanders","Reapers",""), "\\#0000ffMumble \\#0033ffInfo \\#0066ffis \\#0099ffthemoose.typefrag.com \\#00ccffport \\#00ffff9350 \\#00ccffjoin \\#0099ffit \\#0066ffor \\#0033ffbe \\#0000ffkicked.", - PlanetSideGUID(32783), + 15, + 128, + 0, 0, 0, 0, @@ -93,7 +94,9 @@ class OutfitEventTest extends Specification { unk9 = 0, OutfitRankNames("Dog Meat","Russian","","","Squad Leaders","Acting Commanders","Reapers",""), "\\#0000ffMumble \\#0033ffInfo \\#0066ffis \\#0099ffthemoose.typefrag.com \\#00ccffport \\#00ffff9350 \\#00ccffjoin \\#0099ffit \\#0066ffor \\#0033ffbe \\#0000ffkicked.", - PlanetSideGUID(32783), + 15, + 128, + 0, 0, 0, 0, @@ -151,8 +154,10 @@ class OutfitEventTest extends Specification { unk9 = 0, OutfitRankNames("","","","","","","",""), "", - PlanetSideGUID(28672), - 33353, + 0, + 112, + 73, + 130, 0, 0, 0, @@ -179,15 +184,17 @@ class OutfitEventTest extends Specification { unk9 = 0, OutfitRankNames("","","","","","","",""), "", - PlanetSideGUID(28672), - 33353, - 0, + 0, + 112, + 73, + 130, 0, 0, 0, 0, 0, 0, + 0 ) ) ) diff --git a/src/test/scala/game/OutfitListEventTest.scala b/src/test/scala/game/OutfitListEventTest.scala index e7731a2db..c5713a55f 100644 --- a/src/test/scala/game/OutfitListEventTest.scala +++ b/src/test/scala/game/OutfitListEventTest.scala @@ -9,18 +9,18 @@ import org.specs2.mutable._ import scodec.bits.ByteVector class OutfitListEventTest extends Specification { - val unk0_ABC: ByteVector = ByteVector.fromValidHex("98 5 e83a0000 000e1800 0800000 11404e0069006700680074004c006f00720064007300 854e005900430061007400") - val unk0_DEF: ByteVector = ByteVector.fromValidHex("98 4 ec281001 51a62800 3400000 11a0490052004f004e004600490053005400200043006c0061006e00 8654006f006c006a00") - val unk1_ABC: ByteVector = ByteVector.fromValidHex("98 4 723c0000 2aa81e00 2200000 11006900470061006d00650073002d004500 906900670061006d006500730043005400460057006800610063006b002d004500") - val unk2_ABC: ByteVector = ByteVector.fromValidHex("98 4 9a3c0001 16da4e00 0400000 11a042006c006f006f00640020006f0066002000560061006e007500 864b00610072006e002d004500") - val unk3_ABC: ByteVector = ByteVector.fromValidHex("98 4 9c3c0000 df587c00 1400000 11a054006800650020004e00650076006500720068006f006f006400 8e6f00460058006f00530074006f006e0065004d0061006e002d004700") - val unk4_ABC: ByteVector = ByteVector.fromValidHex("98 4 c03c0000 24060400 0600000 1220540068006500200042006c00610063006b0020004b006e0069006700680074007300 874400720061007a00760065006e00") - val unk5_ABC: ByteVector = ByteVector.fromValidHex("98 5 383c0001 4b709a00 0c00000 10a03e005400760053003c00 89430061007000650062006f00610074007300") - val unk6_ABC: ByteVector = ByteVector.fromValidHex("98 5 b03c0000 35d67000 0400000 11404c006f0073007400200043006100750073006500 895a00650072006f004b00650077006c006c00") - val unk7_ABC: ByteVector = ByteVector.fromValidHex("98 4 043e0001 9fb82616 1400000 11e0540068006500200042006c00610063006b00200054006f00770065007200 874b00720075007000680065007800") + val unk2_0_ABC: ByteVector = ByteVector.fromValidHex("98 5 e83a0000 000e1800 0800000 11404e0069006700680074004c006f00720064007300 854e005900430061007400") + val unk2_0_DEF: ByteVector = ByteVector.fromValidHex("98 4 ec281001 51a62800 3400000 11a0490052004f004e004600490053005400200043006c0061006e00 8654006f006c006a00") + val unk2_1_ABC: ByteVector = ByteVector.fromValidHex("98 4 723c0000 2aa81e00 2200000 11006900470061006d00650073002d004500 906900670061006d006500730043005400460057006800610063006b002d004500") + val unk2_2_ABC: ByteVector = ByteVector.fromValidHex("98 4 9a3c0001 16da4e00 0400000 11a042006c006f006f00640020006f0066002000560061006e007500 864b00610072006e002d004500") + val unk2_3_ABC: ByteVector = ByteVector.fromValidHex("98 4 9c3c0000 df587c00 1400000 11a054006800650020004e00650076006500720068006f006f006400 8e6f00460058006f00530074006f006e0065004d0061006e002d004700") + val unk2_4_ABC: ByteVector = ByteVector.fromValidHex("98 4 c03c0000 24060400 0600000 1220540068006500200042006c00610063006b0020004b006e0069006700680074007300 874400720061007a00760065006e00") + val unk2_5_ABC: ByteVector = ByteVector.fromValidHex("98 5 383c0001 4b709a00 0c00000 10a03e005400760053003c00 89430061007000650062006f00610074007300") + val unk2_6_ABC: ByteVector = ByteVector.fromValidHex("98 5 b03c0000 35d67000 0400000 11404c006f0073007400200043006100750073006500 895a00650072006f004b00650077006c006c00") + val unk2_7_ABC: ByteVector = ByteVector.fromValidHex("98 4 043e0001 9fb82616 1400000 11e0540068006500200042006c00610063006b00200054006f00770065007200 874b00720075007000680065007800") "decode unk0_ABC" in { - PacketCoding.decodePacket(unk0_ABC).require match { + PacketCoding.decodePacket(unk2_0_ABC).require match { case OutfitListEvent(code, ListElementOutfit(unk1, points, members, outfit_name, outfit_leader)) => code mustEqual OutfitListEvent.RequestType.ListElementOutfit unk1 mustEqual 7668 @@ -37,7 +37,7 @@ class OutfitListEventTest extends Specification { val msg = OutfitListEvent(RequestType.ListElementOutfit, ListElementOutfit(7668, 788224, 4, "NightLords", "NYCat")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector - pkt mustEqual unk0_ABC + pkt mustEqual unk2_0_ABC } } diff --git a/src/test/scala/game/OutfitMemberEventTest.scala b/src/test/scala/game/OutfitMemberEventTest.scala index 0317b8343..5dbcef004 100644 --- a/src/test/scala/game/OutfitMemberEventTest.scala +++ b/src/test/scala/game/OutfitMemberEventTest.scala @@ -10,42 +10,29 @@ import scodec.bits._ class OutfitMemberEventTest extends Specification { //val unk0_ABC: ByteVector = hex"90 3518 4000 1a4e 4100 2 180 450078007000650072007400 8483 07e0 119d bfe0 70" // 0x90048640001030c28022404c0061007a00650072003100390038003200f43a45e00b4c604010 -val unk0_ABC_Lazer: ByteVector = hex"90 048640001030c28022404c0061007a00650072003100390038003200f43a45e00b4c604010" + val unk0_ABC_Lazer = hex"90 0 4864 0001 030c 2802 24 0 4c0061007a00650072003100390038003200 f43a 45e0 0b4c 6040 10" - val OpolE = hex"90 0 4864 0003 aad6 280a 14 0 4f0070006f006c004500 c9a1 80e0 0d03 2040 10" - val Billy = hex"90 0 4864 0003 a41a 280a 20 0 620069006c006c007900320035003600 935f 6000 186a b040 50" - val Lazer = hex"90 0 4864 0001 030c 2802 24 0 4c0061007a00650072003100390038003200 e6dc 25a0 153e 6040 10" - val Virus = hex"90 0 4864 0002 1b64 4c02 28 0 5600690072007500730047006900760065007200 2f89 0080 0000 0000 10" - val PvtPa = hex"90 0 4864 0000 1e69 e80a 2c 0 500076007400500061006e00630061006b0065007300 705e a080 0a85 e060 10" - val Night = hex"90 0 4864 0002 4cf0 3802 28 0 4e006900670068007400770069006e0067003100 b8fb 9a40 0da6 ec80 50" + val OpolE = hex"90 0 4864 0003 aad6 280a 14 0 4f0070006f006c004500 c9a1 80e0 0d03 2040 10" + val Billy = hex"90 0 4864 0003 a41a 280a 20 0 620069006c006c007900320035003600 935f 6000 186a b040 50" + val Lazer = hex"90 0 4864 0001 030c 2802 24 0 4c0061007a00650072003100390038003200 e6dc 25a0 153e 6040 10" + val Virus = hex"90 0 4864 0002 1b64 4c02 28 0 5600690072007500730047006900760065007200 2f89 0080 0000 0000 10" + val PvtPa = hex"90 0 4864 0000 1e69 e80a 2c 0 500076007400500061006e00630061006b0065007300 705e a080 0a85 e060 10" + val Night = hex"90 0 4864 0002 4cf0 3802 28 0 4e006900670068007400770069006e0067003100 b8fb 9a40 0da6 ec80 50" - /* - OutfitMemberEvent(0, ValidPlanetSideGUID(6418), 0, 0, 64, 195, 10, 0, Lazer1982, 230, 220, 37, 160, 21, 62, 96, 64, 16, BitVector(empty)) - OutfitMemberEvent(0, ValidPlanetSideGUID(6418), 0, 0, 7, 154, 122, 2, PvtPancakes, 112, 94, 160, 128, 10, 133, 224, 96, 16, BitVector(empty)) - OutfitMemberEvent(0, ValidPlanetSideGUID(6418), 0, 0, 134, 217, 19, 0, VirusGiver, 47, 137, 0, 128, 0, 0, 0, 0, 16, BitVector(empty)) - OutfitMemberEvent(0, ValidPlanetSideGUID(6418), 0, 0, 234, 181, 138, 2, OpolE, 201, 161, 128, 224, 13, 3, 32, 64, 16, BitVector(empty)) - OutfitMemberEvent(0, ValidPlanetSideGUID(6418), 0, 0, 233, 6, 138, 2, billy256, 147, 95, 96, 0, 24, 106, 176, 64, 80, BitVector(empty)) - - - */ + val Unk0 = hex"90 5 40542002 3f61e808 0" "decode Unk0 ABC" in { PacketCoding.decodePacket(unk0_ABC_Lazer).require match { - case OutfitMemberEvent(unk00, outfit_guid, unk3, unk5, member_name, unk8, unk9, unk10, unk11, unk12, unk13,unk14,unk15,unk16) => - unk00 mustEqual 0 - outfit_guid mustEqual 6418L - unk3 mustEqual 49984 - unk5 mustEqual 10 + case OutfitMemberEvent(action, outfit_id, member_id, member_name, rank, points, last_login, action2, padding) => + action mustEqual 0 + outfit_id mustEqual 6418L + member_id mustEqual 705344 member_name mustEqual "Lazer1982" - unk8 mustEqual 244 - unk9 mustEqual 58 - unk10 mustEqual 69 - unk11 mustEqual 224 - unk12 mustEqual 11 - unk13 mustEqual 76 - unk14 mustEqual 96 - unk15 mustEqual 64 - unk16 mustEqual 16 + rank mustEqual 7 + points mustEqual 3134113 + last_login mustEqual 156506 + action2 mustEqual 1 + padding mustEqual ByteVector(0x0) case _ => ko } @@ -53,20 +40,15 @@ val unk0_ABC_Lazer: ByteVector = hex"90 048640001030c28022404c0061007a00650 "encode Unk0 ABC" in { val msg = OutfitMemberEvent( - unk00 = 0, + action = 0, outfit_id = 6418L, - unk3 = 49984, - unk5 = 10, + member_id = 705344, member_name = "Lazer1982", - unk8 = 244, - unk9 = 58, - unk10 = 69, - unk11 = 224, - unk12 = 11, - unk13 = 76, - unk14 = 96, - unk15 = 64, - unk16 = 16, + rank = 7, + points = 3134113, + last_login = 156506, + action2 = 1, + ByteVector.empty ) val pkt = PacketCoding.encodePacket(msg).require.toByteVector diff --git a/src/test/scala/game/OutfitMembershipRequestTest.scala b/src/test/scala/game/OutfitMembershipRequestTest.scala index bef384a5b..0e8af6e4c 100644 --- a/src/test/scala/game/OutfitMembershipRequestTest.scala +++ b/src/test/scala/game/OutfitMembershipRequestTest.scala @@ -13,7 +13,7 @@ class OutfitMembershipRequestTest extends Specification { 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 unk2 = hex"8c 5 bb399e0 2000 0000 1140 7600690072007500730067006900760065007200" // -- virusgiver + val invite_old = hex"8c 5 bb399e0 2000 0000 1140 7600690072007500730067006900760065007200" // -- virusgiver val unk3 = hex"8c 5 bb399e0 2000 0000 1080 750072006f006200" // -- "urob" -- could be false positive -- seems to gets an OMSResp -> 0x8d271bb399e025af8f405080550072006f0062008080 val accept_1 = hex"8c 6 0200 000 1000" val accept_2 = hex"8c 6 0400 000 1000" @@ -23,19 +23,24 @@ class OutfitMembershipRequestTest extends Specification { val cancel_1_abc = hex"8c a 0200 000 0000 0000 1060 610062006300" val cancel_3_def = hex"8c a 0600 000 0000 0000 1060 640065006600" // /outfitcancel 123 def -- first parameter is skipped + // dumped from half implemented outfit + val invite = hex"8c4020000000000000116069006e00760069007400650054006500730074003100" + val kick = hex"8cc020000017ac8f405000" + val setrank = hex"8ce020000017ac8f404600" // setting rank from 0 to 1 + "decode CreateOutfit ABC" in { PacketCoding.decodePacket(create_ABC).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Create - avatar_id mustEqual 1 - action mustEqual CreateOutfit("", 0, unk4 = false, "ABC") + outfit_id mustEqual 1 + action mustEqual Create("", "ABC") case _ => ko } } "encode CreateOutfit ABC" in { - val msg = OutfitMembershipRequest(RequestType.Create, 1, CreateOutfit("", 0, unk4 = false, "ABC")) + val msg = OutfitMembershipRequest(RequestType.Create, 1, Create("", "ABC")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual create_ABC @@ -43,17 +48,17 @@ class OutfitMembershipRequestTest extends Specification { "decode CreateOutfit 2222" in { PacketCoding.decodePacket(create_2222).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Create - avatar_id mustEqual 8 - action mustEqual CreateOutfit("", 0, unk4 = false, "2222") + outfit_id mustEqual 8 + action mustEqual Create("", "2222") case _ => ko } } "encode CreateOutfit 2222" in { - val msg = OutfitMembershipRequest(RequestType.Create, 8, CreateOutfit("", 0, unk4 = false, "2222")) + val msg = OutfitMembershipRequest(RequestType.Create, 8, Create("", "2222")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual create_2222 @@ -61,17 +66,17 @@ class OutfitMembershipRequestTest extends Specification { "decode FormOutfit abc" in { PacketCoding.decodePacket(form_abc).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Form - avatar_id mustEqual 1 - action mustEqual FormOutfit("", 0, unk4 = false, "abc") + outfit_id mustEqual 1 + action mustEqual Form("", "abc") case _ => ko } } "encode FormOutfit abc" in { - val msg = OutfitMembershipRequest(RequestType.Form, 1, FormOutfit("", 0, unk4 = false, "abc")) + val msg = OutfitMembershipRequest(RequestType.Form, 1, Form("", "abc")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual form_abc @@ -79,53 +84,53 @@ class OutfitMembershipRequestTest extends Specification { "decode FormOutfit 1" in { PacketCoding.decodePacket(form_1).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Form - avatar_id mustEqual 8 - action mustEqual FormOutfit("", 0, unk4 = false, "1") + outfit_id mustEqual 8 + action mustEqual Form("", "1") case _ => ko } } "encode FormOutfit 1" in { - val msg = OutfitMembershipRequest(RequestType.Form, 8, FormOutfit("", 0, unk4 = false, "1")) + val msg = OutfitMembershipRequest(RequestType.Form, 8, Form("", "1")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual form_1 } - "decode Unk2" in { - PacketCoding.decodePacket(unk2).require match { + "decode Invite" in { + PacketCoding.decodePacket(invite_old).require match { case OutfitMembershipRequest(request_type, outfit_id, action) => - request_type mustEqual RequestType.Unk2 + request_type mustEqual RequestType.Invite outfit_id mustEqual 30383325L - action mustEqual Unk2(0, 0, "virusgiver") + action mustEqual Invite(0, "virusgiver") case _ => ko } } - "encode Unk2" in { - val msg = OutfitMembershipRequest(RequestType.Unk2, 30383325L, Unk2(0, 0, "virusgiver")) + "encode Invite" in { + val msg = OutfitMembershipRequest(RequestType.Invite, 30383325L, Invite(0, "virusgiver")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector - pkt mustEqual unk2 + pkt mustEqual invite_old } "decode AcceptOutfitInvite 1" in { PacketCoding.decodePacket(accept_1).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Accept - avatar_id mustEqual 1 - action mustEqual AcceptOutfitInvite("") + outfit_id mustEqual 1 + action mustEqual AcceptInvite("") case _ => ko } } "encode AcceptOutfitInvite 1" in { - val msg = OutfitMembershipRequest(RequestType.Accept, 1, AcceptOutfitInvite("")) + val msg = OutfitMembershipRequest(RequestType.Accept, 1, AcceptInvite("")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual accept_1 @@ -133,17 +138,17 @@ class OutfitMembershipRequestTest extends Specification { "decode AcceptOutfitInvite 2" in { PacketCoding.decodePacket(accept_2).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Accept - avatar_id mustEqual 2 - action mustEqual AcceptOutfitInvite("") + outfit_id mustEqual 2 + action mustEqual AcceptInvite("") case _ => ko } } "encode AcceptOutfitInvite 2" in { - val msg = OutfitMembershipRequest(RequestType.Accept, 2, AcceptOutfitInvite("")) + val msg = OutfitMembershipRequest(RequestType.Accept, 2, AcceptInvite("")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual accept_2 @@ -151,17 +156,17 @@ class OutfitMembershipRequestTest extends Specification { "decode RejectOutfitInvite 1" in { PacketCoding.decodePacket(reject_1).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Reject - avatar_id mustEqual 1 - action mustEqual RejectOutfitInvite("") + outfit_id mustEqual 1 + action mustEqual RejectInvite("") case _ => ko } } "encode RejectOutfitInvite 1" in { - val msg = OutfitMembershipRequest(RequestType.Reject, 1, RejectOutfitInvite("")) + val msg = OutfitMembershipRequest(RequestType.Reject, 1, RejectInvite("")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual reject_1 @@ -169,17 +174,17 @@ class OutfitMembershipRequestTest extends Specification { "decode RejectOutfitInvite 2" in { PacketCoding.decodePacket(reject_2).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Reject - avatar_id mustEqual 2 - action mustEqual RejectOutfitInvite("") + outfit_id mustEqual 2 + action mustEqual RejectInvite("") case _ => ko } } "encode RejectOutfitInvite 2" in { - val msg = OutfitMembershipRequest(RequestType.Reject, 2, RejectOutfitInvite("")) + val msg = OutfitMembershipRequest(RequestType.Reject, 2, RejectInvite("")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual reject_2 @@ -187,17 +192,17 @@ class OutfitMembershipRequestTest extends Specification { "decode CancelOutfitInvite 3" in { PacketCoding.decodePacket(cancel_3).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Cancel - avatar_id mustEqual 3 - action mustEqual CancelOutfitInvite(0, 0, "") + outfit_id mustEqual 3 + action mustEqual CancelInvite(0, "") case _ => ko } } "encode CancelOutfitInvite 3" in { - val msg = OutfitMembershipRequest(RequestType.Cancel, 3, CancelOutfitInvite(0, 0, "")) + val msg = OutfitMembershipRequest(RequestType.Cancel, 3, CancelInvite(0, "")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual cancel_3 @@ -205,17 +210,17 @@ class OutfitMembershipRequestTest extends Specification { "decode CancelOutfitInvite 1 abc" in { PacketCoding.decodePacket(cancel_1_abc).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Cancel - avatar_id mustEqual 1 - action mustEqual CancelOutfitInvite(0, 0, "abc") + outfit_id mustEqual 1 + action mustEqual CancelInvite(0, "abc") case _ => ko } } "encode CancelOutfitInvite 1 abc" in { - val msg = OutfitMembershipRequest(RequestType.Cancel, 1, CancelOutfitInvite(0, 0, "abc")) + val msg = OutfitMembershipRequest(RequestType.Cancel, 1, CancelInvite(0, "abc")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual cancel_1_abc @@ -223,19 +228,81 @@ class OutfitMembershipRequestTest extends Specification { "decode CancelOutfitInvite 3 def" in { PacketCoding.decodePacket(cancel_3_def).require match { - case OutfitMembershipRequest(request_type, avatar_id, action) => + case OutfitMembershipRequest(request_type, outfit_id, action) => request_type mustEqual RequestType.Cancel - avatar_id mustEqual 3 - action mustEqual CancelOutfitInvite(0, 0, "def") + outfit_id mustEqual 3 + action mustEqual CancelInvite(0, "def") case _ => ko } } "encode CancelOutfitInvite 3 def" in { - val msg = OutfitMembershipRequest(RequestType.Cancel, 3, CancelOutfitInvite(0, 0, "def")) + val msg = OutfitMembershipRequest(RequestType.Cancel, 3, CancelInvite(0, "def")) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual cancel_3_def } + + // + + "decode invite" in { + PacketCoding.decodePacket(invite).require match { + case OutfitMembershipRequest(request_type, outfit_id, Invite(unk1, member_name)) => + request_type mustEqual RequestType.Invite + outfit_id mustEqual 1 + unk1 mustEqual 0 + member_name mustEqual "inviteTest1" + case _ => + ko + } + } + + "encode invite" in { + val msg = OutfitMembershipRequest(RequestType.Invite, 1, Invite(0, "inviteTest1")) + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual invite + } + + + "decode kick" in { + PacketCoding.decodePacket(kick).require match { + case OutfitMembershipRequest(request_type, outfit_id, Kick(avatar_id, member_name)) => + request_type mustEqual RequestType.Kick + outfit_id mustEqual 1 + avatar_id mustEqual 41575613 + member_name mustEqual "" + case _ => + ko + } + } + + "encode kick" in { + val msg = OutfitMembershipRequest(RequestType.Kick, 1, Kick(41575613, "")) + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual kick + } + + "decode setrank" in { + PacketCoding.decodePacket(setrank).require match { + case OutfitMembershipRequest(request_type, outfit_id, SetRank(avatar_id, rank, member_name)) => + request_type mustEqual RequestType.SetRank + outfit_id mustEqual 1 + avatar_id mustEqual 41575613 + rank mustEqual 1 + member_name mustEqual "" + case _ => + ko + } + } + + "encode setrank" in { + val msg = OutfitMembershipRequest(RequestType.SetRank, 1, SetRank(41575613, 1, "")) + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual setrank + } + }