mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-19 18:14:44 +00:00
Merge branch 'create-shortcut'
This commit is contained in:
commit
e78afe0d0d
|
|
@ -366,7 +366,7 @@ object GamePacketOpcode extends Enumeration {
|
|||
case 0x26 => noDecoder(UnuseItemMessage)
|
||||
case 0x27 => noDecoder(ObjectDetachMessage)
|
||||
// 0x28
|
||||
case 0x28 => noDecoder(CreateShortcutMessage)
|
||||
case 0x28 => game.CreateShortcutMessage.decode
|
||||
case 0x29 => noDecoder(ChangeShortcutBankMessage)
|
||||
case 0x2a => noDecoder(ObjectAttachMessage)
|
||||
case 0x2b => noDecoder(UnknownMessage43)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
// Copyright (c) 2016 PSForever.net to present
|
||||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
|
||||
/**
|
||||
* Details regarding this shortcut.<br>
|
||||
* <br>
|
||||
* The parameters `purpose` and `tile` are closely related.
|
||||
* These two fields are consistent for all shortcuts of the same type.
|
||||
* `purpose` indicates the purpose of the shortcut.
|
||||
* `tile` is related to what kind of graphic is displayed in this shortcut's slot on the hotbar based on its purpose.
|
||||
* The parameters `effect1` and `effect2` are exclusive to text macro shortcuts and are defaulted to empty `String`s.<br>
|
||||
* <br>
|
||||
* The `shortcut_macro` setting displays a word bubble superimposed by the (first three letters of) `effect1` text.<br>
|
||||
* Implants and the medkit should have self-explanatory graphics.
|
||||
* <br>
|
||||
* Purpose:<br>
|
||||
* `0 - Medkit`<br>
|
||||
* `1 - Macro`<br>
|
||||
* `2 - Implant`<br>
|
||||
* <br>
|
||||
* Tile:<br>
|
||||
* `advanced_regen` (regeneration)<br>
|
||||
* `audio_amplifier`<br>
|
||||
* `darklight_vision`<br>
|
||||
* `medkit`<br>
|
||||
* `melee_booster`<br>
|
||||
* `personal_shield`<br>
|
||||
* `range_magnifier`<br>
|
||||
* `second_wind`<br>
|
||||
* `shortcut_macro`<br>
|
||||
* `silent_run` (sensor shield)<br>
|
||||
* `surge`<br>
|
||||
* `targeting` (enhanced targetting)<br>
|
||||
* <br>
|
||||
* Exploration:<br>
|
||||
* What is `purpose` when 3?
|
||||
* @param purpose the primary use of this shortcut
|
||||
* @param tile the visual element of the shortcut
|
||||
* @param effect1 for macros, a three letter acronym displayed in the hotbar
|
||||
* @param effect2 for macros, the chat message content
|
||||
*/
|
||||
final case class Shortcut(purpose : Int,
|
||||
tile : String,
|
||||
effect1 : String = "",
|
||||
effect2 : String = "")
|
||||
|
||||
/**
|
||||
* Facilitate a quick-use button for the hotbar.<br>
|
||||
* <br>
|
||||
* The hotbar is the eight quick-use slots along the bottom center of the HUD.
|
||||
* Each of these slots is the application of a medkit, or use of an implant, or repetition of a text macro.
|
||||
* There are actually sixty-four of these slots, eight bound to the Function keys depending on which set is selected.<br>
|
||||
* <br>
|
||||
* When `addShortcut` is `true`, the provided `Shortcut` will be defined and attached to the respective hotbar slot indicated by `slot`.
|
||||
* If it is `false`, the given `slot` will be unbound.
|
||||
* Nothing happens if the `slot` selection is invalid.
|
||||
* @param player_guid the player
|
||||
* @param slot the hotbar slot number (one-indexed)
|
||||
* @param unk na; always zero?
|
||||
* @param addShortcut true, if we are adding a shortcut; false, if we are removing any current shortcut
|
||||
* @param shortcut optional; details about the shortcut to be created
|
||||
* @see ChangeShortcutBankMessage
|
||||
*/
|
||||
final case class CreateShortcutMessage(player_guid : PlanetSideGUID,
|
||||
slot : Int,
|
||||
unk : Int,
|
||||
addShortcut : Boolean,
|
||||
shortcut : Option[Shortcut] = None)
|
||||
extends PlanetSideGamePacket {
|
||||
type Packet = CreateShortcutMessage
|
||||
def opcode = GamePacketOpcode.CreateShortcutMessage
|
||||
def encode = CreateShortcutMessage.encode(this)
|
||||
}
|
||||
|
||||
object Shortcut extends Marshallable[Shortcut] {
|
||||
// Convenient predefined Shortcuts for the Medkit and Implants
|
||||
/**
|
||||
* Preset for the Audio Amplifier implant. */
|
||||
final val AUDIO_AMPLIFIER : Some[Shortcut] = Some(Shortcut(2, "audio_amplifier"))
|
||||
/**
|
||||
* Preset for the Darklight Vision implant. */
|
||||
final val DARKLIGHT_VISION : Some[Shortcut] = Some(Shortcut(2, "darklight_vision"))
|
||||
/**
|
||||
* Preset for the Enhanced Targeting implant. */
|
||||
final val ENHANCED_TARGETING : Some[Shortcut] = Some(Shortcut(2, "targeting"))
|
||||
/**
|
||||
* Preset for the medkit quick-use option. */
|
||||
final val MEDKIT : Some[Shortcut] = Some(Shortcut(0, "medkit"))
|
||||
/**
|
||||
* Preset for the Melee Booster implant. */
|
||||
final val MELEE_BOOSTER : Some[Shortcut] = Some(Shortcut(2, "melee_booster"))
|
||||
/**
|
||||
* Preset for the Personal Shield implant. */
|
||||
final val PERSONAL_SHIELD : Some[Shortcut] = Some(Shortcut(2, "personal_shield"))
|
||||
/**
|
||||
* Preset for the Range Magnifier implant. */
|
||||
final val RANGE_MAGNIFIER : Some[Shortcut] = Some(Shortcut(2, "range_magnifier"))
|
||||
/**
|
||||
* Preset for the Regeneration implant. */
|
||||
final val REGENERATION : Some[Shortcut] = Some(Shortcut(2, "advanced_regen"))
|
||||
/**
|
||||
* Preset for the Second Wind implant. */
|
||||
final val SECOND_WIND : Some[Shortcut] = Some(Shortcut(2, "second_wind"))
|
||||
/**
|
||||
* Preset for the Sensor Shield implant. */
|
||||
final val SENSOR_SHIELD : Some[Shortcut] = Some(Shortcut(2, "silent_run"))
|
||||
/**
|
||||
* Preset for the Surge implant. */
|
||||
final val SURGE : Some[Shortcut] = Some(Shortcut(2, "surge"))
|
||||
/**
|
||||
* Converter for text macro parameters that acts like a preset.
|
||||
* @param effect1 a three letter acronym displayed in the hotbar
|
||||
* @param effect2 the chat message content
|
||||
* @return `Some` shortcut that represents a voice macro command
|
||||
*/
|
||||
def MACRO(effect1 : String, effect2 : String) : Some[Shortcut] = Some(Shortcut(1, "shortcut_macro", effect1, effect2))
|
||||
|
||||
implicit val codec : Codec[Shortcut] = (
|
||||
("purpose" | uint2L) ::
|
||||
("tile" | PacketHelpers.encodedStringAligned(5)) ::
|
||||
("effect1" | PacketHelpers.encodedWideString) ::
|
||||
("effect2" | PacketHelpers.encodedWideString)
|
||||
).as[Shortcut]
|
||||
}
|
||||
|
||||
object CreateShortcutMessage extends Marshallable[CreateShortcutMessage] {
|
||||
implicit val codec : Codec[CreateShortcutMessage] = (
|
||||
("player_guid" | PlanetSideGUID.codec) ::
|
||||
("slot" | uint8L) ::
|
||||
("unk" | uint8L) ::
|
||||
(("addShortcut" | bool) >>:~ { value =>
|
||||
conditional(value, "shortcut" | Shortcut.codec).hlist
|
||||
})
|
||||
).as[CreateShortcutMessage]
|
||||
}
|
||||
|
|
@ -300,6 +300,113 @@ class GamePacketTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
"CreateShortcutMessage" should {
|
||||
val stringMedkit = hex"28 7210 01 00 90 C0 6D65646B6974 80 80"
|
||||
val stringMacro = hex"28 4C05 08 00 B1 C0 73686F72746375745F6D6163726F 83 4E00 5400 5500 9B 2F00 7000 6C00 6100 7400 6F00 6F00 6E00 2000 4900 6E00 6300 6F00 6D00 6900 6E00 6700 2000 4E00 5400 5500 2000 7300 7000 6100 6D00 2100"
|
||||
val stringRemove = hex"28 4C05 01 00 00"
|
||||
|
||||
"decode (medkit)" in {
|
||||
PacketCoding.DecodePacket(stringMedkit).require match {
|
||||
case CreateShortcutMessage(player_guid, slot, unk, addShortcut, shortcut) =>
|
||||
player_guid mustEqual PlanetSideGUID(4210)
|
||||
slot mustEqual 1
|
||||
unk mustEqual 0
|
||||
addShortcut mustEqual true
|
||||
shortcut.isDefined mustEqual true
|
||||
shortcut.get.purpose mustEqual 0
|
||||
shortcut.get.tile mustEqual "medkit"
|
||||
shortcut.get.effect1 mustEqual ""
|
||||
shortcut.get.effect2 mustEqual ""
|
||||
case default =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"decode (macro)" in {
|
||||
PacketCoding.DecodePacket(stringMacro).require match {
|
||||
case CreateShortcutMessage(player_guid, slot, unk, addShortcut, shortcut) =>
|
||||
player_guid mustEqual PlanetSideGUID(1356)
|
||||
slot mustEqual 8
|
||||
unk mustEqual 0
|
||||
addShortcut mustEqual true
|
||||
shortcut.isDefined mustEqual true
|
||||
shortcut.get.purpose mustEqual 1
|
||||
shortcut.get.tile mustEqual "shortcut_macro"
|
||||
shortcut.get.effect1 mustEqual "NTU"
|
||||
shortcut.get.effect2 mustEqual "/platoon Incoming NTU spam!"
|
||||
case default =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"decode (remove)" in {
|
||||
PacketCoding.DecodePacket(stringRemove).require match {
|
||||
case CreateShortcutMessage(player_guid, slot, unk, addShortcut, shortcut) =>
|
||||
player_guid mustEqual PlanetSideGUID(1356)
|
||||
slot mustEqual 1
|
||||
unk mustEqual 0
|
||||
addShortcut mustEqual false
|
||||
shortcut.isDefined mustEqual false
|
||||
case default =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"encode (medkit)" in {
|
||||
val msg = CreateShortcutMessage(PlanetSideGUID(4210), 1, 0, true, Some(Shortcut(0, "medkit")))
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual stringMedkit
|
||||
}
|
||||
|
||||
"encode (macro)" in {
|
||||
val msg = CreateShortcutMessage(PlanetSideGUID(1356), 8, 0, true, Some(Shortcut(1, "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, false)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual stringRemove
|
||||
}
|
||||
|
||||
"macro" in {
|
||||
val MACRO : Some[Shortcut] = Shortcut.MACRO("NTU", "/platoon Incoming NTU spam!")
|
||||
MACRO.get.purpose mustEqual 1
|
||||
MACRO.get.tile mustEqual "shortcut_macro"
|
||||
MACRO.get.effect1 mustEqual "NTU"
|
||||
MACRO.get.effect2 mustEqual "/platoon Incoming NTU spam!"
|
||||
}
|
||||
|
||||
"presets" in {
|
||||
Shortcut.AUDIO_AMPLIFIER.get.purpose mustEqual 2
|
||||
Shortcut.AUDIO_AMPLIFIER.get.tile mustEqual "audio_amplifier"
|
||||
Shortcut.DARKLIGHT_VISION.get.purpose mustEqual 2
|
||||
Shortcut.DARKLIGHT_VISION.get.tile mustEqual "darklight_vision"
|
||||
Shortcut.ENHANCED_TARGETING.get.purpose mustEqual 2
|
||||
Shortcut.ENHANCED_TARGETING.get.tile mustEqual "targeting"
|
||||
Shortcut.MEDKIT.get.purpose mustEqual 0
|
||||
Shortcut.MEDKIT.get.tile mustEqual "medkit"
|
||||
Shortcut.MELEE_BOOSTER.get.purpose mustEqual 2
|
||||
Shortcut.MELEE_BOOSTER.get.tile mustEqual "melee_booster"
|
||||
Shortcut.PERSONAL_SHIELD.get.purpose mustEqual 2
|
||||
Shortcut.PERSONAL_SHIELD.get.tile mustEqual "personal_shield"
|
||||
Shortcut.RANGE_MAGNIFIER.get.purpose mustEqual 2
|
||||
Shortcut.RANGE_MAGNIFIER.get.tile mustEqual "range_magnifier"
|
||||
Shortcut.REGENERATION.get.purpose mustEqual 2
|
||||
Shortcut.REGENERATION.get.tile mustEqual "advanced_regen"
|
||||
Shortcut.SECOND_WIND.get.purpose mustEqual 2
|
||||
Shortcut.SECOND_WIND.get.tile mustEqual "second_wind"
|
||||
Shortcut.SENSOR_SHIELD.get.purpose mustEqual 2
|
||||
Shortcut.SENSOR_SHIELD.get.tile mustEqual "silent_run"
|
||||
Shortcut.SURGE.get.purpose mustEqual 2
|
||||
Shortcut.SURGE.get.tile mustEqual "surge"
|
||||
}
|
||||
}
|
||||
|
||||
"DropItemMessage" should {
|
||||
val string = hex"37 4C00"
|
||||
|
||||
|
|
|
|||
|
|
@ -171,6 +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, true, Shortcut.MEDKIT)))
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
|
|
|||
Loading…
Reference in a new issue