diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 6e9984e5d..412da85fa 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -506,7 +506,7 @@ object GamePacketOpcode extends Enumeration { case 0x9c => noDecoder(DebugDrawMessage) case 0x9d => noDecoder(SoulMarkMessage) case 0x9e => noDecoder(UplinkPositionEvent) - case 0x9f => noDecoder(HotSpotUpdateMessage) + case 0x9f => game.HotSpotUpdateMessage.decode // OPCODES 0xa0-af case 0xa0 => game.BuildingInfoUpdateMessage.decode diff --git a/common/src/main/scala/net/psforever/packet/game/HotSpotUpdateMessage.scala b/common/src/main/scala/net/psforever/packet/game/HotSpotUpdateMessage.scala new file mode 100644 index 000000000..9309f3ab7 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/HotSpotUpdateMessage.scala @@ -0,0 +1,50 @@ +// Copyright (c) 2016 PSForever.net to present +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import scodec.Codec +import scodec.codecs._ + +/** + * na + * @param unk na + * @param x the x-coord of the center of the hotspot + * @param y the y-coord of the center of the hotspot + * @param scale the scaling of the hotspot graphic + */ +final case class HotSpotInfo(unk : Int, + x : Int, + y : Int, + scale : Int) + +/** + * na + * @param continent_guid the zone (continent) + * @param unk na + * @param spots a list of HotSpotInfo, or Nil if empty + */ +// TODO test for size > 0 (e.g., > hex'00') +// TODO test for size > 15 (e.g., > hex'F0') +final case class HotSpotUpdateMessage(continent_guid : PlanetSideGUID, + unk : Int, + spots : List[HotSpotInfo] = Nil) + extends PlanetSideGamePacket { + type Packet = HotSpotUpdateMessage + def opcode = GamePacketOpcode.HotSpotUpdateMessage + def encode = HotSpotUpdateMessage.encode(this) +} + +object HotSpotUpdateMessage extends Marshallable[HotSpotUpdateMessage] { + implicit val hotspot_codec : Codec[HotSpotInfo] = { + ("unk" | uint8L) :: + ("x" | uint16L) :: + ("y" | uint16L) :: + ("scale" | uintL(20)) + }.as[HotSpotInfo] + + implicit val codec : Codec[HotSpotUpdateMessage] = ( + ("continent_guid" | PlanetSideGUID.codec) :: + ("unk" | uint8L) :: + ("spots" | listOfN(uint8L, hotspot_codec)) + ).as[HotSpotUpdateMessage] +} diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index 2f7e8a11d..0f88abdfe 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -915,6 +915,27 @@ class GamePacketTest extends Specification { } } + "HotSpotUpdateMessage" should { + val stringClear = hex"9F 0500 10 00" + + "decode (clear)" in { + PacketCoding.DecodePacket(stringClear).require match { + case HotSpotUpdateMessage(continent_guid, unk, spots) => + continent_guid mustEqual PlanetSideGUID(5) + unk mustEqual 16 + spots.size mustEqual 0 + case _ => + ko + } + } + + "encode (clear)" in { + val msg = HotSpotUpdateMessage(PlanetSideGUID(5),16) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual stringClear + } + } + "BuildingInfoUpdateMessage" should { val string = hex"a0 04 00 09 00 16 00 00 00 00 80 00 00 00 17 00 00 00 00 00 00 40"