diff --git a/common/src/main/scala/net/psforever/packet/game/CreateShortcutMessage.scala b/common/src/main/scala/net/psforever/packet/game/CreateShortcutMessage.scala index f3bcd4da9..bdd77ed8e 100644 --- a/common/src/main/scala/net/psforever/packet/game/CreateShortcutMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/CreateShortcutMessage.scala @@ -6,7 +6,7 @@ import scodec.Codec import scodec.codecs._ /** - * Create a quick-use button for the hotbar.
+ * Details regarding this shortcut. *
* Purpose:
* `advanced_regen` (regeneration)
@@ -20,52 +20,65 @@ import scodec.codecs._ * `shortcut_macro`
* `silent_run` (sensor shield)
* `surge`
- * `targeting` - * @param player_guid the player - * @param slot the hotbar slot number (one-indexed) - * @param unk1 na - * @param unk2 na + * `targeting` (enchanced targetting) * @param purpose the primary purpose/use of this shortcut * @param effect1 for macros, a three letter acronym displayed in the hotbar * @param effect2 for macros, the chat message content */ -//TODO must handle case 0x28 xxxx 01 00 00 for moving shortcuts +final case class Shortcut(purpose : String, + effect1 : String = "", + effect2 : String = "") + +/** + * Manipulate a quick-use button for the hotbar. + *
+ * na + * @param player_guid the player + * @param slot the hotbar slot number (one-indexed) + * @param unk1 na + * @param unk2 na + * @param shortcut optional; details about the shortcut to be created + */ final case class CreateShortcutMessage(player_guid : PlanetSideGUID, slot : Int, unk1 : Int, unk2 : Int, - purpose : String = "", - effect1 : String = "", - effect2 : String = "") + shortcut : Option[Shortcut] = None) extends PlanetSideGamePacket { type Packet = CreateShortcutMessage def opcode = GamePacketOpcode.CreateShortcutMessage def encode = CreateShortcutMessage.encode(this) } -//* -object CreateShortcutMessage extends Marshallable[CreateShortcutMessage] { - implicit val codec : Codec[CreateShortcutMessage] = ( - ("player_guid" | PlanetSideGUID.codec) :: - ("slot" | uint8L) :: - ("unk1" | uint8L) :: - ("unk2" | uintL(3)) :: - ("purpose" | PacketHelpers.encodedStringAligned(5)) :: + +object Shortcut extends Marshallable[Shortcut] { + // Needs to be Marshallable[T] for .as[T] to work its magic on the type of the codec Codec[T] + implicit val codec : Codec[Shortcut] = ( + ("purpose" | PacketHelpers.encodedStringAligned(5)) :: ("effect1" | PacketHelpers.encodedWideString) :: ("effect2" | PacketHelpers.encodedWideString) - ).as[CreateShortcutMessage] + ).as[Shortcut] + + // Convenient predefined Shortcuts for the Medkit and Implants + final val AUDIO_AMPLIFIER : Shortcut = Shortcut("audio_amplifier") + final val DARKLIGHT_VISION : Shortcut = Shortcut("darklight_vision") + final val ENHANCED_TARGETING = Shortcut("targeting") + final val MEDKIT : Shortcut = Shortcut("medkit") + final val MELEE_BOOSTER : Shortcut = Shortcut("melee_booster") + final val PERSONAL_SHIELD : Shortcut = Shortcut("personal_shield") + final val RANGE_MAGNIFIER : Shortcut = Shortcut("range_magnifier") + final val REGENERATION : Shortcut = Shortcut("advanced_regen") + final val SECOND_WIND : Shortcut = Shortcut("second_wind") + final val SENSOR_SHIELD : Shortcut = Shortcut("silent_run") + final val SURGE : Shortcut = Shortcut("surge") } -// */ -/* + object CreateShortcutMessage extends Marshallable[CreateShortcutMessage] { implicit val codec : Codec[CreateShortcutMessage] = ( ("player_guid" | PlanetSideGUID.codec) :: ("slot" | uint8L) :: ("unk1" | uint8L) :: - ("unk2" | uintL(3)) >>:~ ( value => - conditional(value.last > 0, "purpose" | PacketHelpers.encodedStringAligned(5)) :: - conditional(value.last > 0, "effect1" | PacketHelpers.encodedWideString) :: - conditional(value.last > 0, "effect2" | PacketHelpers.encodedWideString) - ) + (("unk2" | uintL(3)) >>:~ { value => + conditional(value > 0, "shortcut" | Shortcut.codec).hlist + }) ).as[CreateShortcutMessage] } -// */ diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index 19a8c3262..ab89e8789 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -307,14 +307,15 @@ class GamePacketTest extends Specification { "decode (medkit)" in { PacketCoding.DecodePacket(stringMedkit).require match { - case CreateShortcutMessage(player_guid, slot, unk1, unk2, purpose, effect1, effect2) => + case CreateShortcutMessage(player_guid, slot, unk1, unk2, shortcut) => player_guid mustEqual PlanetSideGUID(4210) slot mustEqual 1 unk1 mustEqual 0 unk2 mustEqual 4 - purpose mustEqual "medkit" - effect1 mustEqual "" - effect2 mustEqual "" + shortcut.isDefined mustEqual true + shortcut.get.purpose mustEqual "medkit" + shortcut.get.effect1 mustEqual "" + shortcut.get.effect2 mustEqual "" case default => ko } @@ -322,14 +323,15 @@ class GamePacketTest extends Specification { "decode (implant)" in { PacketCoding.DecodePacket(stringImplant).require match { - case CreateShortcutMessage(player_guid, slot, unk1, unk2, purpose, effect1, effect2) => + case CreateShortcutMessage(player_guid, slot, unk1, unk2, shortcut) => player_guid mustEqual PlanetSideGUID(4210) slot mustEqual 4 unk1 mustEqual 0 unk2 mustEqual 6 - purpose mustEqual "surge" - effect1 mustEqual "" - effect2 mustEqual "" + shortcut.isDefined mustEqual true + shortcut.get.purpose mustEqual "surge" + shortcut.get.effect1 mustEqual "" + shortcut.get.effect2 mustEqual "" case default => ko } @@ -337,14 +339,15 @@ class GamePacketTest extends Specification { "decode (macro)" in { PacketCoding.DecodePacket(stringMacro).require match { - case CreateShortcutMessage(player_guid, slot, unk1, unk2, purpose, effect1, effect2) => + case CreateShortcutMessage(player_guid, slot, unk1, unk2, shortcut) => player_guid mustEqual PlanetSideGUID(1356) slot mustEqual 8 unk1 mustEqual 0 unk2 mustEqual 5 - purpose mustEqual "shortcut_macro" - effect1 mustEqual "NTU" - effect2 mustEqual "/platoon Incoming NTU spam!" + shortcut.isDefined mustEqual true + shortcut.get.purpose mustEqual "shortcut_macro" + shortcut.get.effect1 mustEqual "NTU" + shortcut.get.effect2 mustEqual "/platoon Incoming NTU spam!" case default => ko } @@ -352,42 +355,40 @@ class GamePacketTest extends Specification { "decode (remove)" in { PacketCoding.DecodePacket(stringRemove).require match { - case CreateShortcutMessage(player_guid, slot, unk1, unk2, purpose, effect1, effect2) => + case CreateShortcutMessage(player_guid, slot, unk1, unk2, shortcut) => player_guid mustEqual PlanetSideGUID(1356) slot mustEqual 1 unk1 mustEqual 0 unk2 mustEqual 0 - purpose mustEqual "" - effect1 mustEqual "" - effect2 mustEqual "" + shortcut.isDefined mustEqual false case default => ko } } "encode (medkit)" in { - val msg = CreateShortcutMessage(PlanetSideGUID(4210), 1, 0, 4, "medkit") + val msg = CreateShortcutMessage(PlanetSideGUID(4210), 1, 0, 4, Some(Shortcut("medkit"))) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual stringMedkit } "encode (implant)" in { - val msg = CreateShortcutMessage(PlanetSideGUID(4210), 4, 0, 6, "surge") + val msg = CreateShortcutMessage(PlanetSideGUID(4210), 4, 0, 6, Some(Shortcut("surge"))) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual stringImplant } "encode (macro)" in { - val msg = CreateShortcutMessage(PlanetSideGUID(1356), 8, 0, 5, "shortcut_macro", "NTU", "/platoon Incoming NTU spam!") + val msg = CreateShortcutMessage(PlanetSideGUID(1356), 8, 0, 5, Some(Shortcut("shortcut_macro", "NTU", "/platoon Incoming NTU spam!"))) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual stringMacro } "encode (remove)" in { - val msg = CreateShortcutMessage(PlanetSideGUID(1356), 1, 0, 0, "") + val msg = CreateShortcutMessage(PlanetSideGUID(1356), 1, 0, 0) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual stringRemove diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 625838e79..4902709da 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -171,7 +171,7 @@ class WorldSessionActor extends Actor with MDCContextAware { true))) //Boosted generator room pain field sendResponse(PacketCoding.CreateGamePacket(0, SetCurrentAvatarMessage(PlanetSideGUID(guid),0,0))) - sendResponse(PacketCoding.CreateGamePacket(0, CreateShortcutMessage(PlanetSideGUID(guid), 1, 0, 6, "medkit"))) + sendResponse(PacketCoding.CreateGamePacket(0, CreateShortcutMessage(PlanetSideGUID(guid), 1, 0, 6, Some(Shortcut.MEDKIT)))) import scala.concurrent.duration._ import scala.concurrent.ExecutionContext.Implicits.global