diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 8f6e0097..75d7a45b 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -399,7 +399,7 @@ object GamePacketOpcode extends Enumeration { case DismountVehicleCargoMsg => noDecoder(opcode) case CargoMountPointStatusMessage => noDecoder(opcode) case BeginZoningMessage => noDecoder(opcode) - case ItemTransactionMessage => noDecoder(opcode) + case ItemTransactionMessage => game.ItemTransactionMessage.decode case ItemTransactionResultMessage => noDecoder(opcode) // OPCODE 70 diff --git a/common/src/main/scala/net/psforever/packet/game/ItemTransactionMessage.scala b/common/src/main/scala/net/psforever/packet/game/ItemTransactionMessage.scala new file mode 100644 index 00000000..a174a22a --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/ItemTransactionMessage.scala @@ -0,0 +1,30 @@ +// Copyright (c) 2016 PSForever.net to present +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} +import net.psforever.types.TransactionType +import scodec.Codec +import scodec.codecs._ + +final case class ItemTransactionMessage(terminal_guid : PlanetSideGUID, + transaction_type : TransactionType.Value, + item_page : Int, + item_name : String, + unk1 : Int, + item_guid : PlanetSideGUID) + extends PlanetSideGamePacket { + type Packet = ItemTransactionMessage + def opcode = GamePacketOpcode.ItemTransactionMessage + def encode = ItemTransactionMessage.encode(this) +} + +object ItemTransactionMessage extends Marshallable[ItemTransactionMessage] { + implicit val codec : Codec[ItemTransactionMessage] = ( + ("terminal_guid" | PlanetSideGUID.codec) :: + ("transaction_type" | TransactionType.codec) :: + ("item_page" | uint16L) :: + ("item_name" | PacketHelpers.encodedStringAligned(5)) :: + ("unk1" | uint8L) :: + ("item_guid" | PlanetSideGUID.codec) + ).as[ItemTransactionMessage] +} diff --git a/common/src/main/scala/net/psforever/types/TransactionType.scala b/common/src/main/scala/net/psforever/types/TransactionType.scala new file mode 100644 index 00000000..c1b640b7 --- /dev/null +++ b/common/src/main/scala/net/psforever/types/TransactionType.scala @@ -0,0 +1,20 @@ +// Copyright (c) 2016 PSForever.net to present +package net.psforever.types + +import net.psforever.packet.PacketHelpers +import scodec.codecs._ + +object TransactionType extends Enumeration { + type Type = Value + val Unk0, + Unk1, + Buy, + Sell, + Unk4, + Unk5, + Unk6, + Unk7 + = Value + + implicit val codec = PacketHelpers.createEnumerationCodec(this, uintL(3)) +} diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index c2ce00bc..da9aa495 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -519,5 +519,66 @@ class GamePacketTest extends Specification { pkt mustEqual string } } + + "ItemTransactionMessage" should { + val string_buy = hex"44 4C03 4000110070756E6973686572000000" + val string_sell = hex"44 5303 60001000004E00" + val string_forget = hex"44 BA00 600011006861726173736572000000" + + "decode" in { + PacketCoding.DecodePacket(string_buy).require match { + case ItemTransactionMessage(terminal_guid, transaction_type, item_page, item_name, unk1, item_guid) => + terminal_guid mustEqual PlanetSideGUID(844) + transaction_type mustEqual TransactionType.Buy + item_page mustEqual 0 + item_name mustEqual "punisher" + unk1 mustEqual 0 + item_guid mustEqual PlanetSideGUID(0) + case default => + ko + } + + PacketCoding.DecodePacket(string_sell).require match { + case ItemTransactionMessage(terminal_guid, transaction_type, item_page, item_name, unk1, item_guid) => + terminal_guid mustEqual PlanetSideGUID(851) + transaction_type mustEqual TransactionType.Sell + item_page mustEqual 0 + item_name mustEqual "" + unk1 mustEqual 0 + item_guid mustEqual PlanetSideGUID(78) + case default => + ko + } + + PacketCoding.DecodePacket(string_forget).require match { + case ItemTransactionMessage(terminal_guid, transaction_type, item_page, item_name, unk1, item_guid) => + terminal_guid mustEqual PlanetSideGUID(186) + transaction_type mustEqual TransactionType.Sell + item_page mustEqual 0 + item_name mustEqual "harasser" + unk1 mustEqual 0 + item_guid mustEqual PlanetSideGUID(0) + case default => + ko + } + } + + "encode" in { + val msg_buy = ItemTransactionMessage(PlanetSideGUID(844), TransactionType.Buy, 0, "punisher", 0, PlanetSideGUID(0)) + val pkt_buy = PacketCoding.EncodePacket(msg_buy).require.toByteVector + + pkt_buy mustEqual string_buy + + val msg_sell = ItemTransactionMessage(PlanetSideGUID(851), TransactionType.Sell, 0, "", 0, PlanetSideGUID(78)) + val pkt_sell = PacketCoding.EncodePacket(msg_sell).require.toByteVector + + pkt_sell mustEqual string_sell + + val msg_forget = ItemTransactionMessage(PlanetSideGUID(186), TransactionType.Sell, 0, "harasser", 0, PlanetSideGUID(0)) + val pkt_forget = PacketCoding.EncodePacket(msg_forget).require.toByteVector + + pkt_forget mustEqual string_forget + } + } } } diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 7d059bff..6fe09271 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -203,6 +203,9 @@ class WorldSessionActor extends Actor with MDCContextAware { case msg @ GenericObjectStateMsg(object_guid, unk1) => log.info("GenericObjectState: " + msg) + case msg @ ItemTransactionMessage(terminal_guid, transaction_type, item_page, item_name, unk1, item_guid) => + log.info("ItemTransaction: " + msg) + case default => log.debug(s"Unhandled GamePacket ${pkt}") }