diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 4300e22af..1117b9f4f 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -13,8 +13,6 @@ import scala.annotation.switch * UnknownMessage* means that there, to the best of our knowledge, was no opcode of this value. * This was double checked by extracting out the master case statement in PlanetsideComm::OnReceive * and by parsing NetMessage RTTI. - * - * Keep http://psforever.net/wiki/Game_Packets up-to-date with the decoding progress of each packet */ object GamePacketOpcode extends Enumeration { type Type = Value @@ -311,13 +309,13 @@ object GamePacketOpcode extends Enumeration { ClientCheatedMessage // last known message type (243, 0xf3) = Value - private def noDecoder(opcode : GamePacketOpcode.Type) = (a : BitVector) => + private def noDecoder(opcode : GamePacketOpcode.Type) = (_ : BitVector) => Attempt.failure(Err(s"Could not find a marshaller for game packet $opcode")) /// Mapping of packet IDs to decoders. Notice that we are using the @switch annotation which ensures that the Scala /// compiler will be able to optimize this as a lookup table (switch statement). Microbenchmarks show a nearly 400x /// speedup when using a switch (given the worst case of not finding a decoder) - def getPacketDecoder(opcode : GamePacketOpcode.Type) : (BitVector) => Attempt[DecodeResult[PlanetSideGamePacket]] = (opcode.id : @switch) match { + def getPacketDecoder(opcode : GamePacketOpcode.Type) : BitVector => Attempt[DecodeResult[PlanetSideGamePacket]] = (opcode.id : @switch) match { // OPCODES 0x00-0f case 0x00 => noDecoder(Unknown0) case 0x01 => game.LoginMessage.decode @@ -492,7 +490,7 @@ object GamePacketOpcode extends Enumeration { // OPCODES 0x90-9f case 0x90 => noDecoder(OutfitMemberEvent) case 0x91 => noDecoder(OutfitMemberUpdate) - case 0x92 => noDecoder(PlanetsideStringAttributeMessage) + case 0x92 => game.PlanetsideStringAttributeMessage.decode case 0x93 => noDecoder(DataChallengeMessage) case 0x94 => noDecoder(DataChallengeMessageResp) case 0x95 => game.WeatherMessage.decode diff --git a/common/src/main/scala/net/psforever/packet/game/PlanetsideStringAttributeMessage.scala b/common/src/main/scala/net/psforever/packet/game/PlanetsideStringAttributeMessage.scala new file mode 100644 index 000000000..542cc2d75 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/PlanetsideStringAttributeMessage.scala @@ -0,0 +1,31 @@ +// Copyright (c) 2016 PSForever.net to present +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} +import scodec.Codec +import scodec.codecs._ + +/** + * na
+ * The one common use of this packet is to transmit information about the name of the player's outfit during login. + * The guid will belong to the player; the "type will be 0; the outfit name will appear on the appropriate window. + * @param guid na + * @param string_type na + * @param string_value na + */ +final case class PlanetsideStringAttributeMessage(guid : PlanetSideGUID, + string_type : Int, + string_value : String) + extends PlanetSideGamePacket { + type Packet = PlanetsideStringAttributeMessage + def opcode = GamePacketOpcode.PlanetsideStringAttributeMessage + def encode = PlanetsideStringAttributeMessage.encode(this) +} + +object PlanetsideStringAttributeMessage extends Marshallable[PlanetsideStringAttributeMessage] { + implicit val codec : Codec[PlanetsideStringAttributeMessage] = ( + ("guid" | PlanetSideGUID.codec) :: + ("string_type" | uint8L) :: + ("string_value" | PacketHelpers.encodedWideString) + ).as[PlanetsideStringAttributeMessage] +} diff --git a/common/src/test/scala/game/PlanetsideStringAttributeMessageTest.scala b/common/src/test/scala/game/PlanetsideStringAttributeMessageTest.scala new file mode 100644 index 000000000..41e6d5c92 --- /dev/null +++ b/common/src/test/scala/game/PlanetsideStringAttributeMessageTest.scala @@ -0,0 +1,29 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable.Specification +import net.psforever.packet.PacketCoding +import net.psforever.packet.game._ +import scodec.bits._ + +class PlanetsideStringAttributeMessageTest extends Specification { + val string = hex"92 fb04 00 90540068006500200042006c00610063006b00200052006100760065006e007300" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case PlanetsideStringAttributeMessage(guid, string_type, string_value) => + guid mustEqual PlanetSideGUID(1275) + string_type mustEqual 0 + string_value mustEqual "The Black Ravens" + case _ => + ko + } + } + + "encode" in { + val msg = PlanetsideStringAttributeMessage(PlanetSideGUID(1275), 0, "The Black Ravens") + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +}