diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 1d1f4802..aad4bf0c 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -392,7 +392,7 @@ object GamePacketOpcode extends Enumeration { case 0x3c => game.GenericCollisionMsg.decode case 0x3d => game.QuantityUpdateMessage.decode case 0x3e => game.ArmorChangedMessage.decode - case 0x3f => noDecoder(ProjectileStateMessage) + case 0x3f => game.ProjectileStateMessage.decode // OPCODES 0x40-4f case 0x40 => noDecoder(MountVehicleCargoMsg) diff --git a/common/src/main/scala/net/psforever/packet/game/ProjectileStateMessage.scala b/common/src/main/scala/net/psforever/packet/game/ProjectileStateMessage.scala new file mode 100644 index 00000000..2871cd8f --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/ProjectileStateMessage.scala @@ -0,0 +1,47 @@ +// 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 from the server to render the projectiles of one player's weapon on other players' clients. + * @param projectile_guid the projectile + * @param origin a spawning position for the projectile + * @param orient a directional heading for the projectile + * @param unk1 na; + * rarely not 0 + * @param unk2 na + * @param unk3 na + * @param unk4 na; + * rarely not false + * @param unk5 na + */ +final case class ProjectileStateMessage(projectile_guid : PlanetSideGUID, + origin : Vector3, + orient : Vector3, + unk1 : Int, + unk2 : Int, + unk3 : Int, + unk4 : Boolean, + unk5 : Int) + extends PlanetSideGamePacket { + type Packet = ProjectileStateMessage + def opcode = GamePacketOpcode.ProjectileStateMessage + def encode = ProjectileStateMessage.encode(this) +} + +object ProjectileStateMessage extends Marshallable[ProjectileStateMessage] { + implicit val codec : Codec[ProjectileStateMessage] = ( + ("projectile_guid" | PlanetSideGUID.codec) :: + ("origin" | Vector3.codec_pos) :: + ("orient" | Vector3.codec_float) :: + ("unk1" | uint8L) :: + ("unk2" | uint8L) :: + ("unk3" | uint8L) :: + ("unk4" | bool) :: + ("unk5" | uint16L) + ).as[ProjectileStateMessage] +} diff --git a/common/src/test/scala/game/ProjectileStateMessageTest.scala b/common/src/test/scala/game/ProjectileStateMessageTest.scala new file mode 100644 index 00000000..020a1e80 --- /dev/null +++ b/common/src/test/scala/game/ProjectileStateMessageTest.scala @@ -0,0 +1,44 @@ +// 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 ProjectileStateMessageTest extends Specification { + val string = hex"3f 259d c5019 30e4a 9514 c52c9541 d9ba05c2 c5973941 00 f8 ec 020000" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case ProjectileStateMessage(projectile, pos, aim, unk1, unk2, unk3, unk4, unk5) => + projectile mustEqual PlanetSideGUID(40229) + pos.x mustEqual 4611.539f + pos.y mustEqual 5576.375f + pos.z mustEqual 82.328125f + aim.x mustEqual 18.64686f + aim.y mustEqual -33.43247f + aim.z mustEqual 11.599553f + unk1 mustEqual 0 + unk2 mustEqual 248 + unk3 mustEqual 236 + unk4 mustEqual false + unk5 mustEqual 4 + case _ => + ko + } + } + + "encode" in { + val msg = ProjectileStateMessage( + PlanetSideGUID(40229), + Vector3(4611.539f, 5576.375f, 82.328125f), + Vector3(18.64686f, -33.43247f, 11.599553f), + 0, 248, 236, false, 4 + ) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +}