From 684c64679b2c29a40351ce7399adbc704de156bc Mon Sep 17 00:00:00 2001 From: FateJH Date: Sat, 6 May 2017 00:45:42 -0400 Subject: [PATCH 1/2] initial work on DisplayedAwardMessage packet and tests --- .../psforever/packet/GamePacketOpcode.scala | 2 +- .../packet/game/DisplayedAwardMessage.scala | 59 +++++++++++++++++++ .../game/DisplayedAwardMessageTest.scala | 29 +++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 common/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala create mode 100644 common/src/test/scala/game/DisplayedAwardMessageTest.scala diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index cad22888..a06b26c0 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -567,7 +567,7 @@ object GamePacketOpcode extends Enumeration { // OPCODES 0xd0-df case 0xd0 => noDecoder(UnknownMessage208) - case 0xd1 => noDecoder(DisplayedAwardMessage) + case 0xd1 => game.DisplayedAwardMessage.decode case 0xd2 => noDecoder(RespawnAMSInfoMessage) case 0xd3 => noDecoder(ComponentDamageMessage) case 0xd4 => noDecoder(GenericObjectActionAtPositionMessage) diff --git a/common/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala b/common/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala new file mode 100644 index 00000000..fe0e1215 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala @@ -0,0 +1,59 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.game + +import net.psforever.packet.game.objectcreate.RibbonBars +import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} +import scodec.Codec +import scodec.codecs._ + +/** + * An `Enumeration` of the slots for award ribbons on a player's `RibbonBars`. + */ +object RibbonBarsSlot extends Enumeration { + type Type = Value + + val Top, + Middle, + Bottom, + TermOfService //technically,the slot above "Top" + = Value + + implicit val codec = PacketHelpers.createEnumerationCodec(this, uint4L) +} + +/** + * Dispatched to configure a player's merit commendation ribbons.
+ *
+ * Normally, this packet is dispatched by the client when managing merit commendations through the "Character Info/Achievements" tab. + * On Gemini Live, this packet was also always dispatched once by the server during character login. + * It set the term of service ribbon explicitly. + * Generally, this was unnecessary, as the encoded character data maintains information about displayed ribbons. + * This behavior was probably a routine that ensured that correct yearly progression was tracked if the player earned it while offline. + * It never set any of the other ribbon slot positions during login.
+ *
+ * A specific ribbon may only be set once to one slot. + * The last set slot is considered the valid position to which that ribbon will be placed/moved. + * @param player_guid the player + * @param ribbon the award to be displayed; + * defaults to `RibbonsBars.noRibbon`; + * use `RibbonsBars.noRibbon` when indicating "no ribbon" + * @param bar any of the four positions where the award ribbon is to be displayed; + * defaults to `TermOfService` + * @see `RibbonBars` + */ +final case class DisplayedAwardMessage(player_guid : PlanetSideGUID, + ribbon : Long = RibbonBars.noRibbon, + bar : RibbonBarsSlot.Value = RibbonBarsSlot.TermOfService) + extends PlanetSideGamePacket { + type Packet = DisplayedAwardMessage + def opcode = GamePacketOpcode.DisplayedAwardMessage + def encode = DisplayedAwardMessage.encode(this) +} + +object DisplayedAwardMessage extends Marshallable[DisplayedAwardMessage] { + implicit val codec : Codec[DisplayedAwardMessage] = ( + ("player_guid" | PlanetSideGUID.codec) :: + ("ribbon" | uint32L) :: + ("bar" | RibbonBarsSlot.codec) + ).as[DisplayedAwardMessage] +} diff --git a/common/src/test/scala/game/DisplayedAwardMessageTest.scala b/common/src/test/scala/game/DisplayedAwardMessageTest.scala new file mode 100644 index 00000000..9ad7c1d6 --- /dev/null +++ b/common/src/test/scala/game/DisplayedAwardMessageTest.scala @@ -0,0 +1,29 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class DisplayedAwardMessageTest extends Specification { + val string = hex"D1 9F06 A6010000 3 0" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case DisplayedAwardMessage(player_guid, ribbon, bar) => + player_guid mustEqual PlanetSideGUID(1695) + ribbon mustEqual 422L + bar mustEqual RibbonBarsSlot.TermOfService + case _ => + ko + } + } + + "encode" in { + val msg = DisplayedAwardMessage(PlanetSideGUID(1695), 422L, RibbonBarsSlot.TermOfService) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} From 211079779047d1eca0495340f627d96e4af7b4f2 Mon Sep 17 00:00:00 2001 From: FateJH Date: Sun, 7 May 2017 01:34:55 -0400 Subject: [PATCH 2/2] created a MeritCommendation Enumeration to use with the ribbon awards --- .../packet/game/DisplayedAwardMessage.scala | 11 +- .../game/ObjectCreateDetailedMessage.scala | 11 +- .../packet/game/objectcreate/RibbonBars.scala | 28 +- .../psforever/types/MeritCommendation.scala | 522 ++++++++++++++++++ .../game/DisplayedAwardMessageTest.scala | 5 +- .../ObjectCreateDetailedMessageTest.scala | 8 +- .../scala/game/ObjectCreateMessageTest.scala | 32 +- 7 files changed, 576 insertions(+), 41 deletions(-) create mode 100644 common/src/main/scala/net/psforever/types/MeritCommendation.scala diff --git a/common/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala b/common/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala index fe0e1215..2f7024ad 100644 --- a/common/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala @@ -1,7 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.packet.game -import net.psforever.packet.game.objectcreate.RibbonBars +import net.psforever.types.MeritCommendation import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} import scodec.Codec import scodec.codecs._ @@ -35,14 +35,15 @@ object RibbonBarsSlot extends Enumeration { * The last set slot is considered the valid position to which that ribbon will be placed/moved. * @param player_guid the player * @param ribbon the award to be displayed; - * defaults to `RibbonsBars.noRibbon`; - * use `RibbonsBars.noRibbon` when indicating "no ribbon" + * defaults to `MeritCommendation.None`; + * use `MeritCommendation.None` when indicating "no ribbon" * @param bar any of the four positions where the award ribbon is to be displayed; * defaults to `TermOfService` * @see `RibbonBars` + * @see `MeritCommendation` */ final case class DisplayedAwardMessage(player_guid : PlanetSideGUID, - ribbon : Long = RibbonBars.noRibbon, + ribbon : MeritCommendation.Value = MeritCommendation.None, bar : RibbonBarsSlot.Value = RibbonBarsSlot.TermOfService) extends PlanetSideGamePacket { type Packet = DisplayedAwardMessage @@ -53,7 +54,7 @@ final case class DisplayedAwardMessage(player_guid : PlanetSideGUID, object DisplayedAwardMessage extends Marshallable[DisplayedAwardMessage] { implicit val codec : Codec[DisplayedAwardMessage] = ( ("player_guid" | PlanetSideGUID.codec) :: - ("ribbon" | uint32L) :: + ("ribbon" | MeritCommendation.codec) :: ("bar" | RibbonBarsSlot.codec) ).as[DisplayedAwardMessage] } diff --git a/common/src/main/scala/net/psforever/packet/game/ObjectCreateDetailedMessage.scala b/common/src/main/scala/net/psforever/packet/game/ObjectCreateDetailedMessage.scala index 2f2ab416..4040714f 100644 --- a/common/src/main/scala/net/psforever/packet/game/ObjectCreateDetailedMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/ObjectCreateDetailedMessage.scala @@ -55,8 +55,10 @@ object ObjectCreateDetailedMessage extends Marshallable[ObjectCreateDetailedMess * @param data the data used to construct this type of object * @return an ObjectCreateMessage */ - def apply(objectClass : Int, guid : PlanetSideGUID, parentInfo : ObjectCreateMessageParent, data : ConstructorData) : ObjectCreateDetailedMessage = - ObjectCreateDetailedMessage(0L, objectClass, guid, Some(parentInfo), Some(data)) + def apply(objectClass : Int, guid : PlanetSideGUID, parentInfo : ObjectCreateMessageParent, data : ConstructorData) : ObjectCreateDetailedMessage = { + val parentInfoOpt : Option[ObjectCreateMessageParent] = Some(parentInfo) + ObjectCreateDetailedMessage(ObjectCreateBase.streamLen(parentInfoOpt, data), objectClass, guid, parentInfoOpt, Some(data)) + } /** * An abbreviated constructor for creating `ObjectCreateMessages`, ignoring `parentInfo`. @@ -65,8 +67,9 @@ object ObjectCreateDetailedMessage extends Marshallable[ObjectCreateDetailedMess * @param data the data used to construct this type of object * @return an ObjectCreateMessage */ - def apply(objectClass : Int, guid : PlanetSideGUID, data : ConstructorData) : ObjectCreateDetailedMessage = - ObjectCreateDetailedMessage(0L, objectClass, guid, None, Some(data)) + def apply(objectClass : Int, guid : PlanetSideGUID, data : ConstructorData) : ObjectCreateDetailedMessage = { + ObjectCreateDetailedMessage(ObjectCreateBase.streamLen(None, data), objectClass, guid, None, Some(data)) + } /** * Take the important information of a game piece and transform it into bit data. diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/RibbonBars.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/RibbonBars.scala index 305d9a48..83949ee5 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/RibbonBars.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/RibbonBars.scala @@ -2,35 +2,33 @@ package net.psforever.packet.game.objectcreate import net.psforever.packet.Marshallable +import net.psforever.types.MeritCommendation import scodec.Codec import scodec.codecs._ /** * Enumerate the player-displayed merit commendation awards granted for excellence (or tenacity) in combat. - * These are the medals players wish to brandish on their left pauldron.
- *
- * All merit commendation ribbons are represented by a 32-bit signature. - * The default "no-ribbon" value is `0xFFFFFFFF`, although some illegal values will also work. - * The term of service ribbon can not be modified by the user and will apply itself to its slot automatically when valid. + * These are the medals players wish to brandish on their left pauldron. * @param upper the "top" configurable merit ribbon * @param middle the central configurable merit ribbon * @param lower the lower configurable merit ribbon * @param tos the top-most term of service merit ribbon + * @see `MeritCommendation` + * @see `DisplayedAwardMessage` */ -final case class RibbonBars(upper : Long = RibbonBars.noRibbon, - middle : Long = RibbonBars.noRibbon, - lower : Long = RibbonBars.noRibbon, - tos : Long = RibbonBars.noRibbon) extends StreamBitSize { +final case class RibbonBars(upper : MeritCommendation.Value = MeritCommendation.None, + middle : MeritCommendation.Value = MeritCommendation.None, + lower : MeritCommendation.Value = MeritCommendation.None, + tos : MeritCommendation.Value = MeritCommendation.None + ) extends StreamBitSize { override def bitsize : Long = 128L } object RibbonBars extends Marshallable[RibbonBars] { - val noRibbon : Long = 0xFFFFFFFFL - implicit val codec : Codec[RibbonBars] = ( - ("upper" | uint32L) :: - ("middle" | uint32L) :: - ("lower" | uint32L) :: - ("tos" | uint32L) + ("upper" | MeritCommendation.codec) :: + ("middle" | MeritCommendation.codec) :: + ("lower" | MeritCommendation.codec) :: + ("tos" | MeritCommendation.codec) ).as[RibbonBars] } diff --git a/common/src/main/scala/net/psforever/types/MeritCommendation.scala b/common/src/main/scala/net/psforever/types/MeritCommendation.scala new file mode 100644 index 00000000..7dd056de --- /dev/null +++ b/common/src/main/scala/net/psforever/types/MeritCommendation.scala @@ -0,0 +1,522 @@ +// Copyright (c) 2017 PSForever +package net.psforever.types + +import scodec.{Attempt, Err} +import scodec.codecs._ + +/** + * An `Enumeration` of all merit commendation award categories organized into associated ribbons. + * By astonishing coincidence, with exception of the first ten special awards, the rest of list is in alphabetical order. + */ +object MeritCommendation extends Enumeration { + type Type = Value + + val //0 + FanFaire2005Commander, + FanFaire2005Soldier, + FanFaire2006Atlanta, + HalloweenMassacre2006NC, + HalloweenMassacre2006TR, + HalloweenMassacre2006VS, + FanFaire2007, + FanFaire2008, + FanFaire2009, + AdvancedMedic1, + //10 + AdvancedMedic2, + AdvancedMedic3, + AdvancedMedic4, + AdvancedMedic5, + AdvancedMedic6, + AdvancedMedic7, + AdvancedMedicAssists1, + AdvancedMedicAssists2, + AdvancedMedicAssists3, + AdvancedMedicAssists4, + //20 + AdvancedMedicAssists5, + AdvancedMedicAssists6, + AdvancedMedicAssists7, + AirDefender1, + AirDefender2, + AirDefender3, + AirDefender4, + AirDefender5, + AirDefender6, + AirDefender7, + //30 + AMSSupport1, + AMSSupport2, + AMSSupport3, + AMSSupport4, + AMSSupport5, + AMSSupport6, + AMSSupport7, + AntiVehicular1, + AntiVehicular2, + AntiVehicular3, + //40 + AntiVehicular4, + AntiVehicular5, + AntiVehicular6, + AntiVehicular7, + Avenger1, + Avenger2, + Avenger3, + Avenger4, + Avenger5, + Avenger6, + //50 + Avenger7, + AwardColors, //what? + BendingMovieActor, + BFRAdvanced, + BFRAdvanced2, + BFRAdvanced3, + BFRAdvanced4, + BFRAdvanced5, + BFRBuster1, + BFRBuster2, + //60 + BFRBuster3, + BFRBuster4, + BFRBuster5, + BFRBuster6, + BFRBuster7, + BlackOpsHunter1, + BlackOpsHunter2, + BlackOpsHunter3, + BlackOpsHunter4, + BlackOpsHunter5, + //70 + BlackOpsParticipant, + BlackOpsVictory, + Bombadier1, + Bombadier2, + Bombadier3, + Bombadier4, + Bombadier5, + Bombadier6, + Bombadier7, + BomberAce1, + //80 + BomberAce2, + BomberAce3, + BomberAce4, + BomberAce5, + BomberAce6, + BomberAce7, + Boomer1, + Boomer2, + Boomer3, + Boomer4, + //90 + Boomer5, + Boomer6, + Boomer7, + CalvaryDriver1, + CalvaryDriver2, + CalvaryDriver3, + CalvaryDriver4, + CalvaryDriver5, + CalvaryDriver6, + CalvaryDriver7, + //100 + CalvaryPilot, + CalvaryPilot2, + CalvaryPilot3, + CalvaryPilot4, + CalvaryPilot5, + CalvaryPilot6, + CalvaryPilot7, + CMTopOutfit, + CombatMedic, + CombatMedic2, + //110 + CombatMedic3, + CombatMedic4, + CombatMedic5, + CombatMedic6, + CombatMedic7, + CombatRepair1, + CombatRepair2, + CombatRepair3, + CombatRepair4, + CombatRepair5, + //120 + CombatRepair6, + CombatRepair7, + ContestFirstBR40, + ContestMovieMaker, + ContestMovieMakerOutfit, + ContestPlayerOfTheMonth, + ContestPlayerOfTheYear, + CSAppreciation, + DefenseNC1, + DefenseNC2, + //130 + DefenseNC3, + DefenseNC4, + DefenseNC5, + DefenseNC6, + DefenseNC7, + DefenseTR1, + DefenseTR2, + DefenseTR3, + DefenseTR4, + DefenseTR5, + //40 + DefenseTR6, + DefenseTR7, + DefenseVS1, + DefenseVS2, + DefenseVS3, + DefenseVS4, + DefenseVS5, + DefenseVS6, + DefenseVS7, + DevilDogsMovie, + //150 + DogFighter1, + DogFighter2, + DogFighter3, + DogFighter4, + DogFighter5, + DogFighter6, + DogFighter7, + DriverGunner1, + DriverGunner2, + DriverGunner3, + //160 + DriverGunner4, + DriverGunner5, + DriverGunner6, + DriverGunner7, + EliteAssault0, + EliteAssault1, + EliteAssault2, + EliteAssault3, + EliteAssault4, + EliteAssault5, + //170 + EliteAssault6, + EliteAssault7, + EmeraldVeteran, + Engineer1, + Engineer2, + Engineer3, + Engineer4, + Engineer5, + Engineer6, + EquipmentSupport1, + //180 + EquipmentSupport2, + EquipmentSupport3, + EquipmentSupport4, + EquipmentSupport5, + EquipmentSupport6, + EquipmentSupport7, + EventNCCommander, + EventNCElite, + EventNCSoldier, + EventTRCommander, + //190 + EventTRElite, + EventTRSoldier, + EventVSCommander, + EventVSElite, + EventVSSoldier, + Explorer1, + FiveYearNC, + FiveYearTR, + FiveYearVS, + FourYearNC, + //200 + FourYearTR, + FourYearVS, + GalaxySupport1, + GalaxySupport2, + GalaxySupport3, + GalaxySupport4, + GalaxySupport5, + GalaxySupport6, + GalaxySupport7, + Grenade1, + //210 + Grenade2, + Grenade3, + Grenade4, + Grenade5, + Grenade6, + Grenade7, + GroundGunner1, + GroundGunner2, + GroundGunner3, + GroundGunner4, + //220 + GroundGunner5, + GroundGunner6, + GroundGunner7, + HackingSupport1, + HackingSupport2, + HackingSupport3, + HackingSupport4, + HackingSupport5, + HackingSupport6, + HackingSupport7, + //230 + HeavyAssault1, + HeavyAssault2, + HeavyAssault3, + HeavyAssault4, + HeavyAssault5, + HeavyAssault6, + HeavyAssault7, + HeavyInfantry, + HeavyInfantry2, + HeavyInfantry3, + //240 + HeavyInfantry4, + InfantryExpert1, + InfantryExpert2, + InfantryExpert3, + Jacking, + Jacking2, + Jacking3, + Jacking4, + Jacking5, + Jacking6, + //250 + Jacking7, + KnifeCombat1, + KnifeCombat2, + KnifeCombat3, + KnifeCombat4, + KnifeCombat5, + KnifeCombat6, + KnifeCombat7, + LightInfantry, + LockerCracker1, + //260 + LockerCracker2, + LockerCracker3, + LockerCracker4, + LockerCracker5, + LockerCracker6, + LockerCracker7, + LodestarSupport1, + LodestarSupport2, + LodestarSupport3, + LodestarSupport4, + //270 + LodestarSupport5, + LodestarSupport6, + LodestarSupport7, + Loser, + Loser2, + Loser3, + Loser4, + MarkovVeteran, + Max1, + Max2, + //280 + Max3, + Max4, + Max5, + Max6, + MaxBuster1, + MaxBuster2, + MaxBuster3, + MaxBuster4, + MaxBuster5, + MaxBuster6, + //290 + MediumAssault1, + MediumAssault2, + MediumAssault3, + MediumAssault4, + MediumAssault5, + MediumAssault6, + MediumAssault7, + OneYearNC, + OneYearTR, + OneYearVS, + //300 + Orion1, + Orion2, + Orion3, + Orion4, + Orion5, + Orion6, + Orion7, + Osprey1, + Osprey2, + Osprey3, + //310 + Osprey4, + Osprey5, + Osprey6, + Osprey7, + Phalanx1, + Phalanx2, + Phalanx3, + Phalanx4, + Phalanx5, + Phalanx6, + //320 + Phalanx7, + PSUMaAttendee, + PSUMbAttendee, + QAAppreciation, + ReinforcementHackSpecialist, + ReinforcementInfantrySpecialist, + ReinforcementSpecialist, + ReinforcementVehicleSpecialist, + RouterSupport1, + RouterSupport2, + //330 + RouterSupport3, + RouterSupport4, + RouterSupport5, + RouterSupport6, + RouterSupport7, + RouterTelepadDeploy1, + RouterTelepadDeploy2, + RouterTelepadDeploy3, + RouterTelepadDeploy4, + RouterTelepadDeploy5, + //340 + RouterTelepadDeploy6, + RouterTelepadDeploy7, + ScavengerNC1, + ScavengerNC2, + ScavengerNC3, + ScavengerNC4, + ScavengerNC5, + ScavengerNC6, + ScavengerTR1, + ScavengerTR2, + //350 + ScavengerTR3, + ScavengerTR4, + ScavengerTR5, + ScavengerTR6, + ScavengerVS1, + ScavengerVS2, + ScavengerVS3, + ScavengerVS4, + ScavengerVS5, + ScavengerVS6, + //360 + SixYearNC, + SixYearTR, + SixYearVS, + Sniper1, + Sniper2, + Sniper3, + Sniper4, + Sniper5, + Sniper6, + Sniper7, + //370 + SpecialAssault1, + SpecialAssault2, + SpecialAssault3, + SpecialAssault4, + SpecialAssault5, + SpecialAssault6, + SpecialAssault7, + StandardAssault1, + StandardAssault2, + StandardAssault3, + //380 + StandardAssault4, + StandardAssault5, + StandardAssault6, + StandardAssault7, + StracticsHistorian, + Supply1, + Supply2, + Supply3, + Supply4, + Supply5, + //390 + Supply6, + Supply7, + TankBuster1, + TankBuster2, + TankBuster3, + TankBuster4, + TankBuster5, + TankBuster6, + TankBuster7, + ThreeYearNC, + //400 + ThreeYearTR, + ThreeYearVS, + TinyRoboticSupport1, + TinyRoboticSupport2, + TinyRoboticSupport3, + TinyRoboticSupport4, + TinyRoboticSupport5, + TinyRoboticSupport6, + TinyRoboticSupport7, + Transport1, + //410 + Transport2, + Transport3, + Transport4, + Transport5, + Transport6, + Transport7, + TransportationCitation1, + TransportationCitation2, + TransportationCitation3, + TransportationCitation4, + //420 + TransportationCitation5, + TwoYearNC, + TwoYearTR, + TwoYearVS, + ValentineFemale, + ValentineMale, + WernerVeteran, + XmasGingerman, + XmasSnowman, + XmasSpirit + = Value + + /* + The value None requires special consideration. + - A Long number is required for this Enumeration codec. + - Enumerations are designed to only handle Int numbers. + - A Codec only handles unsigned numbers. + - The value of MeritCommendation.None is intended to be 0xFFFFFFFF, which (a) is 4294967295 as a Long, but (b) is -1 as an Integer. + - Due to (a), an Enumeration can not be used to represent that number. + - Due to (b), a Codec can not be used to convert to that number. + */ + val None = Value(-1) + + /** + * Carefully and explicitly convert between `Codec[Long] -> Long -> Int -> MeritCommendation.Value`. + */ + implicit val codec = uint32L.exmap[MeritCommendation.Value] ( + { + case 0xFFFFFFFFL => + Attempt.successful(MeritCommendation.None) + case n => + if(n > Int.MaxValue) { + Attempt.failure(Err(s"value $n is too high, above maximum integer value ${Int.MaxValue}")) + } + else { + Attempt.successful(MeritCommendation(n.toInt)) + } + }, + { + case MeritCommendation.None => + Attempt.successful(0xFFFFFFFFL) + case enum => + Attempt.successful(enum.id.toLong) + } + ) +} diff --git a/common/src/test/scala/game/DisplayedAwardMessageTest.scala b/common/src/test/scala/game/DisplayedAwardMessageTest.scala index 9ad7c1d6..2c8a5851 100644 --- a/common/src/test/scala/game/DisplayedAwardMessageTest.scala +++ b/common/src/test/scala/game/DisplayedAwardMessageTest.scala @@ -1,6 +1,7 @@ // Copyright (c) 2017 PSForever package game +import net.psforever.types.MeritCommendation import org.specs2.mutable._ import net.psforever.packet._ import net.psforever.packet.game._ @@ -13,7 +14,7 @@ class DisplayedAwardMessageTest extends Specification { PacketCoding.DecodePacket(string).require match { case DisplayedAwardMessage(player_guid, ribbon, bar) => player_guid mustEqual PlanetSideGUID(1695) - ribbon mustEqual 422L + ribbon mustEqual MeritCommendation.TwoYearTR bar mustEqual RibbonBarsSlot.TermOfService case _ => ko @@ -21,7 +22,7 @@ class DisplayedAwardMessageTest extends Specification { } "encode" in { - val msg = DisplayedAwardMessage(PlanetSideGUID(1695), 422L, RibbonBarsSlot.TermOfService) + val msg = DisplayedAwardMessage(PlanetSideGUID(1695), MeritCommendation.TwoYearTR, RibbonBarsSlot.TermOfService) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string diff --git a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala index 4bcebf31..c27f7064 100644 --- a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala +++ b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala @@ -201,10 +201,10 @@ class ObjectCreateDetailedMessageTest extends Specification { char.appearance.is_cloaking mustEqual false char.appearance.charging_pose mustEqual false char.appearance.on_zipline mustEqual false - char.appearance.ribbons.upper mustEqual 0xFFFFFFFFL //none - char.appearance.ribbons.middle mustEqual 0xFFFFFFFFL //none - char.appearance.ribbons.lower mustEqual 0xFFFFFFFFL //none - char.appearance.ribbons.tos mustEqual 0xFFFFFFFFL //none + char.appearance.ribbons.upper mustEqual MeritCommendation.None + char.appearance.ribbons.middle mustEqual MeritCommendation.None + char.appearance.ribbons.lower mustEqual MeritCommendation.None + char.appearance.ribbons.tos mustEqual MeritCommendation.None char.healthMax mustEqual 100 char.health mustEqual 100 char.armor mustEqual 50 //standard exosuit value diff --git a/common/src/test/scala/game/ObjectCreateMessageTest.scala b/common/src/test/scala/game/ObjectCreateMessageTest.scala index b60bb811..5b619687 100644 --- a/common/src/test/scala/game/ObjectCreateMessageTest.scala +++ b/common/src/test/scala/game/ObjectCreateMessageTest.scala @@ -4,7 +4,7 @@ package game import net.psforever.packet._ import net.psforever.packet.game._ import net.psforever.packet.game.objectcreate._ -import net.psforever.types.{CharacterGender, ExoSuitType, GrenadeState, PlanetSideEmpire, Vector3} +import net.psforever.types._ import org.specs2.mutable._ import scodec.bits._ @@ -684,10 +684,10 @@ class ObjectCreateMessageTest extends Specification { pc.appearance.is_cloaking mustEqual false pc.appearance.charging_pose mustEqual false pc.appearance.on_zipline mustEqual false - pc.appearance.ribbons.upper mustEqual 276L - pc.appearance.ribbons.middle mustEqual 239L - pc.appearance.ribbons.lower mustEqual 397L - pc.appearance.ribbons.tos mustEqual 360L + pc.appearance.ribbons.upper mustEqual MeritCommendation.Loser4 + pc.appearance.ribbons.middle mustEqual MeritCommendation.HeavyInfantry3 + pc.appearance.ribbons.lower mustEqual MeritCommendation.TankBuster6 + pc.appearance.ribbons.tos mustEqual MeritCommendation.SixYearNC pc.health mustEqual 255 pc.armor mustEqual 253 pc.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade @@ -780,10 +780,10 @@ class ObjectCreateMessageTest extends Specification { pc.appearance.is_cloaking mustEqual false pc.appearance.charging_pose mustEqual false pc.appearance.on_zipline mustEqual false - pc.appearance.ribbons.upper mustEqual 244L - pc.appearance.ribbons.middle mustEqual 353L - pc.appearance.ribbons.lower mustEqual 33L - pc.appearance.ribbons.tos mustEqual 361L + pc.appearance.ribbons.upper mustEqual MeritCommendation.Jacking + pc.appearance.ribbons.middle mustEqual MeritCommendation.ScavengerTR6 + pc.appearance.ribbons.lower mustEqual MeritCommendation.AMSSupport4 + pc.appearance.ribbons.tos mustEqual MeritCommendation.SixYearTR pc.health mustEqual 0 pc.armor mustEqual 0 pc.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade @@ -1107,7 +1107,12 @@ class ObjectCreateMessageTest extends Specification { false, GrenadeState.None, false, false, false, - RibbonBars(276L, 239L, 397L, 360L) + RibbonBars( + MeritCommendation.Loser4, + MeritCommendation.HeavyInfantry3, + MeritCommendation.TankBuster6, + MeritCommendation.SixYearNC + ) ), 255, 253, UniformStyle.ThirdUpgrade, @@ -1159,7 +1164,12 @@ class ObjectCreateMessageTest extends Specification { false, GrenadeState.None, false, false, false, - RibbonBars(244L, 353L, 33L, 361L) + RibbonBars( + MeritCommendation.Jacking, + MeritCommendation.ScavengerTR6, + MeritCommendation.AMSSupport4, + MeritCommendation.SixYearTR + ) ), 0, 0, UniformStyle.ThirdUpgrade,