From f4fa24f3440a9acc43c6deea0342d8efff34064f Mon Sep 17 00:00:00 2001 From: Fate-JH Date: Fri, 10 Mar 2017 21:37:02 -0500 Subject: [PATCH] Packet: ObjectDetachMessage (#116) * initial ObjectDetachMessage packet and tests * discovered how to orient the dropped item --- .../psforever/packet/GamePacketOpcode.scala | 2 +- .../packet/game/DropItemMessage.scala | 14 ++++- .../packet/game/ObjectDetachMessage.scala | 60 +++++++++++++++++++ .../scala/game/ObjectDetachMessageTest.scala | 35 +++++++++++ .../src/main/scala/WorldSessionActor.scala | 2 + 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 common/src/main/scala/net/psforever/packet/game/ObjectDetachMessage.scala create mode 100644 common/src/test/scala/game/ObjectDetachMessageTest.scala diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 21d4ba9b..b6ab2040 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -364,7 +364,7 @@ object GamePacketOpcode extends Enumeration { case 0x24 => game.SetEmpireMessage.decode case 0x25 => game.EmoteMsg.decode case 0x26 => noDecoder(UnuseItemMessage) - case 0x27 => noDecoder(ObjectDetachMessage) + case 0x27 => game.ObjectDetachMessage.decode // 0x28 case 0x28 => game.CreateShortcutMessage.decode case 0x29 => game.ChangeShortcutBankMessage.decode diff --git a/common/src/main/scala/net/psforever/packet/game/DropItemMessage.scala b/common/src/main/scala/net/psforever/packet/game/DropItemMessage.scala index 5adf3bb9..8e03b546 100644 --- a/common/src/main/scala/net/psforever/packet/game/DropItemMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/DropItemMessage.scala @@ -5,6 +5,18 @@ import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, Plan import scodec.Codec import scodec.codecs._ +/** + * Dispatched by the client when the player's intent is to put an item down on the ground.
+ *
+ * When a player drops an item, it normally appears right under their feet (where they are standing). + * This part of the ground is chosen because it should be the stable. + * Also, those coordinates belonging to the player are the most accessible. + * This process, however, is not automatic. + * The server determines the exact position where the item gets placed.
+ *
+ * This packet is complemented by an `ObjectDetachMessage` packet from the server that performs the actual "dropping." + * @param item_guid the item to be dropped + */ final case class DropItemMessage(item_guid : PlanetSideGUID) extends PlanetSideGamePacket { type Packet = DropItemMessage @@ -14,6 +26,6 @@ final case class DropItemMessage(item_guid : PlanetSideGUID) object DropItemMessage extends Marshallable[DropItemMessage] { implicit val codec : Codec[DropItemMessage] = ( - ("item_guid" | PlanetSideGUID.codec) + "item_guid" | PlanetSideGUID.codec ).as[DropItemMessage] } diff --git a/common/src/main/scala/net/psforever/packet/game/ObjectDetachMessage.scala b/common/src/main/scala/net/psforever/packet/game/ObjectDetachMessage.scala new file mode 100644 index 00000000..8630fc74 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/ObjectDetachMessage.scala @@ -0,0 +1,60 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import net.psforever.types.Vector3 +import scodec.Codec +import scodec.codecs._ + +/** + * Dispatched by the server to cause two associated objects to disentangle from one another.
+ *
+ * `ObjectDetachMessage` is the opposite to `ObjectAttachMessage`. + * When detached, the resulting freed object will be placed at the given coordinates. + * For some container objects, most often static ones, a default placement point does exist. + * This usually matches the position where the original mounting occurred, or is relative to the current position of the container. + * Using a position that is not the mounting one, in this case, counts as a temporary teleport of the character. + * As soon as available, e.g., the end of an animation, the character will rw-appear at the mounting point. + * The object may also have its orientation aspect changed.
+ *
+ * This packet is considered proper response to:
+ * - `DismountVehicleMsg`
+ * - `DropItemMessage` + * @param parent_guid the container/connector object + * @param child_guid the contained/connected object + * @param pos where the contained/connected object will be placed after it has detached + * @param roll the roll of the dropped item; + * every `0x1` is 2.813 degrees; + * every `0x10` is 45-degrees; + * it wraps at `0x0` == `0x80` == top facing up + * @param pitch the pitch of the dropped item; + * every `0x1` is 2.813 degrees; + * every `0x10` is 45-degrees; + * it wraps at `0x0` == `0x80` == top facing up + * @param yaw the yaw of the dropped item; + * every `0x1` is 2.813 degrees counter clockwise from East; + * every `0x10` is 45-degrees; + * it wraps at `0x0` == `0x80` == front facing East + */ +final case class ObjectDetachMessage(parent_guid : PlanetSideGUID, + child_guid : PlanetSideGUID, + pos : Vector3, + roll : Int, + pitch : Int, + yaw : Int) + extends PlanetSideGamePacket { + type Packet = ObjectDetachMessage + def opcode = GamePacketOpcode.ObjectDetachMessage + def encode = ObjectDetachMessage.encode(this) +} + +object ObjectDetachMessage extends Marshallable[ObjectDetachMessage] { + implicit val codec : Codec[ObjectDetachMessage] = ( + ("parent_guid" | PlanetSideGUID.codec) :: + ("child_guid" | PlanetSideGUID.codec) :: + ("pos" | Vector3.codec_pos) :: + ("roll" | uint8L) :: + ("pitch" | uint8L) :: + ("yaw" | uint8L) + ).as[ObjectDetachMessage] +} diff --git a/common/src/test/scala/game/ObjectDetachMessageTest.scala b/common/src/test/scala/game/ObjectDetachMessageTest.scala new file mode 100644 index 00000000..0b2b8605 --- /dev/null +++ b/common/src/test/scala/game/ObjectDetachMessageTest.scala @@ -0,0 +1,35 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import net.psforever.types.Vector3 +import scodec.bits._ + +class ObjectDetachMessageTest extends Specification { + val string = hex"27 640B C609 92F76 01D65 F611 00 00 40" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case ObjectDetachMessage(parent_guid, child_guid, pos, roll, pitch, yaw) => + parent_guid mustEqual PlanetSideGUID(2916) + child_guid mustEqual PlanetSideGUID(2502) + pos.x mustEqual 3567.1406f + pos.y mustEqual 2988.0078f + pos.z mustEqual 71.84375f + roll mustEqual 0 + pitch mustEqual 0 + yaw mustEqual 64 + case _ => + ko + } + } + + "encode" in { + val msg = ObjectDetachMessage(PlanetSideGUID(2916), PlanetSideGUID(2502), Vector3(3567.1406f, 2988.0078f, 71.84375f), 0, 0, 64) + 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 3e10636f..8648ea3a 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -279,6 +279,8 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(PacketCoding.CreateGamePacket(0, EmoteMsg(avatar_guid, emote))) case msg @ DropItemMessage(item_guid) => + //item dropped where you spawn in VS Sanctuary + sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(PlanetSideGUID(75), item_guid, app.pos, 0, 0, 0))) log.info("DropItem: " + msg) case msg @ ReloadMessage(item_guid, ammo_clip, unk1) =>