diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 69629b548..35a4cd105 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -385,7 +385,7 @@ object GamePacketOpcode extends Enumeration { case 0x36 => game.PickupItemMessage.decode case 0x37 => game.DropItemMessage.decode // 0x38 - case 0x38 => noDecoder(InventoryStateMessage) + case 0x38 => game.InventoryStateMessage.decode case 0x39 => game.ChangeFireStateMessage_Start.decode case 0x3a => game.ChangeFireStateMessage_Stop.decode case 0x3b => noDecoder(UnknownMessage59) diff --git a/common/src/main/scala/net/psforever/packet/game/InventoryStateMessage.scala b/common/src/main/scala/net/psforever/packet/game/InventoryStateMessage.scala new file mode 100644 index 000000000..1cf24392c --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/InventoryStateMessage.scala @@ -0,0 +1,51 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import scodec.Codec +import scodec.codecs._ + +/** + * Dispatched by the server to update the value associated with an object in a specific container object.
+ *
+ * The object indicated by `object_guid` must be associated with the inventory (`container_guid`) at the time. + * A common use for this packet is to update weapon data when gaining control over that weapon. + * For example, before boarding any kind of turret for the first time, it's ammunition component will have exactly one shot. + * This shot was established when the turret was first created. + * This information would be displayed in the holster icon across the bottom of the GUI while it is mounted. + * Furthermore, the mounted player will only fire the turret exactly one time. + * This packet can provide the turret with its correct and current amount of ammunition before the player mounts it. + * @param object_guid the object being affected + * @param unk na; + * usually 0 + * @param container_guid the object in which `object_guid` is contained + * @param value an amount with which to update `object_guid` + */ +final case class InventoryStateMessage(object_guid : PlanetSideGUID, + unk : Int, + container_guid : PlanetSideGUID, + value : Long) + extends PlanetSideGamePacket { + type Packet = InventoryStateMessage + def opcode = GamePacketOpcode.InventoryStateMessage + def encode = InventoryStateMessage.encode(this) +} + +object InventoryStateMessage extends Marshallable[InventoryStateMessage] { + /** + * Overloaded constructor that ignores the unknown field. + * @param object_guid the object being affected + * @param container_guid the object in which `object_guid` is contained + * @param value an amount with which to update `object_guid` + * @return an `InventoryStateMessage` object + */ + def apply(object_guid : PlanetSideGUID, container_guid : PlanetSideGUID, value : Long) : InventoryStateMessage = + InventoryStateMessage(object_guid, 0, container_guid, value) + + implicit val codec : Codec[InventoryStateMessage] = ( + ("object_guid" | PlanetSideGUID.codec) :: + ("unk" | uintL(10)) :: + ("container_guid" | PlanetSideGUID.codec) :: + ("value" | uint32L) + ).as[InventoryStateMessage] +} diff --git a/common/src/test/scala/game/InventoryStateMessageTest.scala b/common/src/test/scala/game/InventoryStateMessageTest.scala new file mode 100644 index 000000000..9b0cddfae --- /dev/null +++ b/common/src/test/scala/game/InventoryStateMessageTest.scala @@ -0,0 +1,31 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class InventoryStateMessageTest extends Specification { + val string = hex"38 5C0B 00 3C02 B20000000 0" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case InventoryStateMessage(object_guid, unk, inv_guid, value) => + object_guid mustEqual PlanetSideGUID(2908) + unk mustEqual 0 + inv_guid mustEqual PlanetSideGUID(2800) + value mustEqual 200 + case _ => + ko + } + } + + "encode" in { + val msg = InventoryStateMessage(PlanetSideGUID(2908), 0, PlanetSideGUID(2800), 200) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} +