diff --git a/common/src/main/scala/net/psforever/packet/game/HotSpotUpdateMessage.scala b/common/src/main/scala/net/psforever/packet/game/HotSpotUpdateMessage.scala index f3dc760d..dedccd92 100644 --- a/common/src/main/scala/net/psforever/packet/game/HotSpotUpdateMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/HotSpotUpdateMessage.scala @@ -8,17 +8,15 @@ import scodec.codecs._ /** * Information for positioning a hotspot on the continental map.
*
- * The coordinate values and the scaling value have different endianness than most numbers transmitted as packet data. - * The two unknown values are not part of the positioning system, at least not a part of the coordinates.
- *
* The origin point is the lowest left corner of the map grid. - * On either axis, the other edge of the map is found at the maximum value 4096 (`FFF`). - * The scale is typically set as 128 (`80000`) but can also be made smaller or made absurdly big. + * The coordinates of the hotspot do not match up to the map's internal coordinate system - what you learn using the `/loc` command. + * Hotspot coordinates ranges across from 0 (`000`) to 4096 (`FFF`) on both axes. + * The scale is typically set as 128 (`80000`) but can also be made smaller or even made absurdly big. * @param unk1 na * @param x the x-coord of the center of the hotspot * @param unk2 na * @param y the y-coord of the center of the hotspot - * @param scale the scaling of the hotspot icon + * @param scale how big the hotspot explosion icon appears */ final case class HotSpotInfo(unk1 : Int, x : Int, @@ -52,18 +50,20 @@ final case class HotSpotUpdateMessage(continent_guid : PlanetSideGUID, def encode = HotSpotUpdateMessage.encode(this) } -object HotSpotUpdateMessage extends Marshallable[HotSpotUpdateMessage] { - implicit val hotspot_codec : Codec[HotSpotInfo] = { - ("unk1" | uint8) :: - ("x" | uint(12)) :: - ("unk2" | uint8) :: - ("y" | uint(12)) :: - ("scale" | uint(20)) +object HotSpotInfo extends Marshallable[HotSpotInfo] { + implicit val codec : Codec[HotSpotInfo] = { + ("unk1" | uint8L) :: + ("x" | uintL(12)) :: + ("unk2" | uint8L) :: + ("y" | uintL(12)) :: + ("scale" | uintL(20)) }.as[HotSpotInfo] +} +object HotSpotUpdateMessage extends Marshallable[HotSpotUpdateMessage] { implicit val codec : Codec[HotSpotUpdateMessage] = ( ("continent_guid" | PlanetSideGUID.codec) :: ("unk" | uint4L) :: - ("spots" | listOfN(uint8L, hotspot_codec)) + ("spots" | listOfN(uint8L, HotSpotInfo.codec)) ).as[HotSpotUpdateMessage] } diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index 288c42cf..230a0d6f 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -918,6 +918,7 @@ class GamePacketTest extends Specification { "HotSpotUpdateMessage" should { val stringClear = hex"9F 0500 1 00 0" val stringOne = hex"9F 0500 1 01 0 00 2E9 00 145 80000 0" + val stringTwo = hex"9F 0500 5 02 0 00 D07 00 8CA 80000 00 BEA 00 4C4 80000" "decode (clear)" in { PacketCoding.DecodePacket(stringClear).require match { @@ -930,11 +931,54 @@ class GamePacketTest extends Specification { } } + "decode (one)" in { + PacketCoding.DecodePacket(stringOne).require match { + case HotSpotUpdateMessage(continent_guid, unk, spots) => + continent_guid mustEqual PlanetSideGUID(5) + unk mustEqual 1 + spots.size mustEqual 1 + spots.head.x mustEqual 3730 + spots.head.y mustEqual 1105 + spots.head.scale mustEqual 128 + case _ => + ko + } + } + + "decode (two)" in { + PacketCoding.DecodePacket(stringTwo).require match { + case HotSpotUpdateMessage(continent_guid, unk, spots) => + continent_guid mustEqual PlanetSideGUID(5) + unk mustEqual 5 + spots.size mustEqual 2 + spots.head.x mustEqual 125 + spots.head.y mustEqual 3240 + spots.head.scale mustEqual 128 + spots(1).x mustEqual 3755 + spots(1).y mustEqual 3140 + spots(1).scale mustEqual 128 + case _ => + ko + } + } + "encode (clear)" in { val msg = HotSpotUpdateMessage(PlanetSideGUID(5),1) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual stringClear } + + "encode (one)" in { + val msg = HotSpotUpdateMessage(PlanetSideGUID(5),1, HotSpotInfo(0,3730,0,1105,128)::Nil) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual stringOne + } + + "encode (two)" in { + val msg = HotSpotUpdateMessage(PlanetSideGUID(5),1, HotSpotInfo(0,125,0,3240,128)::HotSpotInfo(0,3755,0,3140,128)::Nil) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual stringOne + } } "BuildingInfoUpdateMessage" should {