diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index b6ab2040..06b742e3 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -382,7 +382,7 @@ object GamePacketOpcode extends Enumeration { case 0x33 => game.ObjectHeldMessage.decode case 0x34 => game.WeaponFireMessage.decode case 0x35 => game.AvatarJumpMessage.decode - case 0x36 => noDecoder(PickupItemMessage) + case 0x36 => game.PickupItemMessage.decode case 0x37 => game.DropItemMessage.decode // 0x38 case 0x38 => noDecoder(InventoryStateMessage) diff --git a/common/src/main/scala/net/psforever/packet/game/PickupItemMessage.scala b/common/src/main/scala/net/psforever/packet/game/PickupItemMessage.scala new file mode 100644 index 00000000..e6358113 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/PickupItemMessage.scala @@ -0,0 +1,39 @@ +// 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 client when the player's intent is to collect an item from the ground.
+ *
+ * When a player faces a freed item on the ground in the game world, a prompt appears that invites him to pick it up. + * Doing so generates this packet. + * The server determines the exact inventory position where the item will get placed. + * If the inventory has insufficient space to accommodate the item, it gets put into the player's hand (on the cursor).
+ *
+ * This packet is complemented by an `ObjectAttachMessage` packet from the server that performs the actual "picking up." + * @param item_guid na + * @param player_guid na + * @param unk1 na + * @param unk2 na + */ +final case class PickupItemMessage(item_guid : PlanetSideGUID, + player_guid : PlanetSideGUID, + unk1 : Int, + unk2 : Int) + extends PlanetSideGamePacket { + type Packet = PickupItemMessage + def opcode = GamePacketOpcode.PickupItemMessage + def encode = PickupItemMessage.encode(this) +} + +object PickupItemMessage extends Marshallable[PickupItemMessage] { + implicit val codec : Codec[PickupItemMessage] = ( + ("item_guid" | PlanetSideGUID.codec) :: + ("player_guid" | PlanetSideGUID.codec) :: + ("unk1" | uint8L) :: + ("unk2" | uint16L) + ).as[PickupItemMessage] +} diff --git a/common/src/test/scala/game/PickupItemMessageTest.scala b/common/src/test/scala/game/PickupItemMessageTest.scala new file mode 100644 index 00000000..34a10360 --- /dev/null +++ b/common/src/test/scala/game/PickupItemMessageTest.scala @@ -0,0 +1,30 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class PickupItemMessageTest extends Specification { + val string = hex"36 5600 4B00 00 0000" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case PickupItemMessage(item_guid, player_guid, unk1, unk2) => + item_guid mustEqual PlanetSideGUID(86) + player_guid mustEqual PlanetSideGUID(75) + unk1 mustEqual 0 + unk2 mustEqual 0 + case _ => + ko + } + } + + "encode" in { + val msg = PickupItemMessage(PlanetSideGUID(86), PlanetSideGUID(75), 0, 0) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 8648ea3a..40da1943 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -283,6 +283,9 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(PlanetSideGUID(75), item_guid, app.pos, 0, 0, 0))) log.info("DropItem: " + msg) + case msg @ PickupItemMessage(item_guid, player_guid, unk1, unk2) => + log.info("PickupItem: " + msg) + case msg @ ReloadMessage(item_guid, ammo_clip, unk1) => log.info("Reload: " + msg) sendResponse(PacketCoding.CreateGamePacket(0, ReloadMessage(item_guid, 123, unk1)))