diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index ed333b14..8855bb51 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -538,7 +538,7 @@ object GamePacketOpcode extends Enumeration { case 0xb7 => noDecoder(DisconnectMessage) // 0xb8 case 0xb8 => noDecoder(ExperienceAddedMessage) - case 0xb9 => noDecoder(OrbitalStrikeWaypointMessage) + case 0xb9 => game.OrbitalStrikeWaypointMessage.decode case 0xba => game.KeepAliveMessage.decode case 0xbb => noDecoder(MapObjectStateBlockMessage) case 0xbc => noDecoder(SnoopMsg) diff --git a/common/src/main/scala/net/psforever/packet/game/OrbitalStrikeWaypointMessage.scala b/common/src/main/scala/net/psforever/packet/game/OrbitalStrikeWaypointMessage.scala new file mode 100644 index 00000000..7623d9c7 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/OrbitalStrikeWaypointMessage.scala @@ -0,0 +1,54 @@ +// Copyright (c) 2016 PSForever.net to present +package net.psforever.packet.game + +import net.psforever.newcodecs.newcodecs +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import scodec.Codec +import scodec.codecs._ +import shapeless.{::, HNil} + +final case class XY(x : Float, + y : Float) + +final case class OrbitalStrikeWaypointMessage(unk : PlanetSideGUID, + coords : Option[XY] = None) + extends PlanetSideGamePacket { + type Packet = OrbitalStrikeWaypointMessage + def opcode = GamePacketOpcode.OrbitalStrikeWaypointMessage + def encode = OrbitalStrikeWaypointMessage.encode(this) +} + +object OrbitalStrikeWaypointMessage extends Marshallable[OrbitalStrikeWaypointMessage] { + def apply(player_guid : PlanetSideGUID, coords : XY) : OrbitalStrikeWaypointMessage = + new OrbitalStrikeWaypointMessage(player_guid, Option(coords)) + + private val coords_value : Codec[XY] = ( + ("x" | newcodecs.q_float(0.0, 8192.0, 20)) :: + ("y" | newcodecs.q_float(0.0, 8192.0, 20)) + ).xmap[XY] ( + { + case x :: y :: HNil => + XY(x, y) + }, + { + case XY(x, y) => + x :: y :: HNil + } + ) + + implicit val codec : Codec[OrbitalStrikeWaypointMessage] = ( + ("unk" | PlanetSideGUID.codec) :: + (bool >>:~ { test => + conditional(test, coords_value).hlist + }) + ).xmap[OrbitalStrikeWaypointMessage] ( + { + case u :: _ :: coords :: HNil => + OrbitalStrikeWaypointMessage(u, coords) + }, + { + case OrbitalStrikeWaypointMessage(u, coords) => + u :: coords.isDefined :: coords :: HNil + } + ) +} diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index 4fb16438..3e33bd53 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -1471,6 +1471,47 @@ class GamePacketTest extends Specification { } } + "OrbitalStrikeWaypointMessage" should { + val string_on = hex"B9 46 0C AA E3 D2 2A 92 00" + val string_off = hex"B9 46 0C 00" + + "decode (on)" in { + PacketCoding.DecodePacket(string_on).require match { + case OrbitalStrikeWaypointMessage(guid, coords) => + guid mustEqual PlanetSideGUID(3142) + coords.isDefined mustEqual true + coords.get.x mustEqual 5518.664f + coords.get.y mustEqual 2212.539f + case default => + ko + } + } + + "decode (off)" in { + PacketCoding.DecodePacket(string_off).require match { + case OrbitalStrikeWaypointMessage(guid, coords) => + guid mustEqual PlanetSideGUID(3142) + coords.isDefined mustEqual false + case default => + ko + } + } + + "encode (on)" in { + val msg = OrbitalStrikeWaypointMessage(PlanetSideGUID(3142), XY(5518.664f, 2212.539f)) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_on + } + + "encode (off)" in { + val msg = OrbitalStrikeWaypointMessage(PlanetSideGUID(3142)) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_off + } + } + "WeaponFireMessage" should { val string = hex"34 44130029272F0B5DFD4D4EC5C00009BEF78172003FC0"