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 {