From 69af5124ba5941be065f326ad6a98c8610776efa Mon Sep 17 00:00:00 2001 From: FateJH Date: Wed, 6 Sep 2017 08:26:28 -0400 Subject: [PATCH] added an Enumeration of certifications --- .../converter/AvatarConverter.scala | 4 +- .../objectcreate/DetailedCharacterData.scala | 29 +++--- .../psforever/types/CertificationType.scala | 79 ++++++++++++++++ .../ObjectCreateDetailedMessageTest.scala | 24 ++++- .../src/main/scala/WorldSessionActor.scala | 94 ++++++++++--------- 5 files changed, 166 insertions(+), 64 deletions(-) create mode 100644 common/src/main/scala/net/psforever/types/CertificationType.scala diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala index e42c22143..6c97c17cf 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala @@ -28,6 +28,7 @@ class AvatarConverter extends ObjectCreateConverter[Player]() { } override def DetailedConstructorData(obj : Player) : Try[DetailedCharacterData] = { + import net.psforever.types.CertificationType._ Success( DetailedCharacterData( MakeAppearanceData(obj), @@ -36,10 +37,9 @@ class AvatarConverter extends ObjectCreateConverter[Player]() { obj.MaxHealth, obj.Health, obj.Armor, - 1, 7, 7, obj.MaxStamina, obj.Stamina, - List(0, 1, 11, 21, 26, 27, 28), //TODO certification list + List(StandardAssault, MediumAssault, ATV, Harasser, StandardExoSuit, AgileExoSuit, ReinforcedExoSuit), //TODO certification list List(), //TODO implant list List.empty[String], //TODO fte list List.empty[String], //TODO tutorial list diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCharacterData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCharacterData.scala index ffae12a5d..e678c3f10 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCharacterData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCharacterData.scala @@ -3,7 +3,7 @@ package net.psforever.packet.game.objectcreate import net.psforever.newcodecs.newcodecs import net.psforever.packet.{Marshallable, PacketHelpers} -import net.psforever.types.ImplantType +import net.psforever.types.{CertificationType, ImplantType} import scodec.{Attempt, Codec} import scodec.codecs._ import shapeless.{::, HNil} @@ -12,9 +12,9 @@ import scala.annotation.tailrec /** * An entry in the `List` of valid implant slots in `DetailedCharacterData`. - * "`activation`" is not necessarily the best word for it ... + * `activation`, if defined, indicates the time remaining (in seconds?) before an implant can be activated. * @param implant the type of implant - * @param activation na + * @param activation the activation timer * @see `ImplantType` */ final case class ImplantEntry(implant : ImplantType.Value, @@ -87,7 +87,7 @@ final case class DetailedCharacterData(appearance : CharacterAppearanceData, unk3 : Int, //7 staminaMax : Int, stamina : Int, - certs : List[Int], + certs : List[CertificationType.Value], implants : List[ImplantEntry], firstTimeEvents : List[String], tutorials : List[String], @@ -98,13 +98,12 @@ final case class DetailedCharacterData(appearance : CharacterAppearanceData, override def bitsize : Long = { //factor guard bool values into the base size, not corresponding optional fields, unless contained or enumerated val appearanceSize = appearance.bitsize - val varBit : Option[Int] = CharacterAppearanceData.altModelBit(appearance) val certSize = (certs.length + 1) * 8 //cert list var implantSize : Long = 0L //implant list for(entry <- implants) { implantSize += entry.bitsize } - val implantPadding = DetailedCharacterData.implantFieldPadding(implants, varBit) + val implantPadding = DetailedCharacterData.implantFieldPadding(implants, CharacterAppearanceData.altModelBit(appearance)) val fteLen = firstTimeEvents.size //fte list var eventListSize : Long = 32L + DetailedCharacterData.ftePadding(fteLen, implantPadding) for(str <- firstTimeEvents) { @@ -127,28 +126,28 @@ final case class DetailedCharacterData(appearance : CharacterAppearanceData, object DetailedCharacterData extends Marshallable[DetailedCharacterData] { /** - * Overloaded constructor for `DetailedCharacterData` that allows for a not-optional inventory. + * Overloaded constructor for `DetailedCharacterData` that requires an inventory and drops unknown values. * @param appearance data about the avatar's basic aesthetics + * @param bep the avatar's battle experience points, which determines his Battle Rank + * @param cep the avatar's command experience points, which determines his Command Rank * @param healthMax for `x / y` of hitpoints, this is the avatar's `y` value * @param health for `x / y` of hitpoints, this is the avatar's `x` value * @param armor for `x / y` of armor points, this is the avatar's `x` value - * @param unk1 na - * @param unk2 na - * @param unk3 na * @param staminaMax for `x / y` of stamina points, this is the avatar's `y` value * @param stamina for `x / y` of stamina points, this is the avatar's `x` value - * @param certs na + * @param certs the `List` of active certifications + * @param implants the `List` of implant slots currently possessed by this avatar * @param firstTimeEvents the list of first time events performed by this avatar * @param tutorials the list of tutorials completed by this avatar * @param inventory the avatar's inventory * @param drawn_slot the holster that is initially drawn * @return a `DetailedCharacterData` object */ - def apply(appearance : CharacterAppearanceData, bep : Long, cep : Long, healthMax : Int, health : Int, armor : Int, unk1 : Int, unk2 : Int, unk3 : Int, staminaMax : Int, stamina : Int, certs : List[Int], implants : List[ImplantEntry], firstTimeEvents : List[String], tutorials : List[String], inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedCharacterData = - new DetailedCharacterData(appearance, bep, cep, healthMax, health, armor, unk1, unk2, unk3, staminaMax, stamina, certs, implants, firstTimeEvents, tutorials, Some(inventory), drawn_slot) + def apply(appearance : CharacterAppearanceData, bep : Long, cep : Long, healthMax : Int, health : Int, armor : Int, staminaMax : Int, stamina : Int, certs : List[CertificationType.Value], implants : List[ImplantEntry], firstTimeEvents : List[String], tutorials : List[String], inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedCharacterData = + new DetailedCharacterData(appearance, bep, cep, healthMax, health, armor, 1, 7, 7, staminaMax, stamina, certs, implants, firstTimeEvents, tutorials, Some(inventory), drawn_slot) /** - * `Codec` for entires in the list of implants. + * `Codec` for entries in the `List` of implants. */ private val implant_entry_codec : Codec[ImplantEntry] = ( ("implant" | ImplantType.codec) :: @@ -285,7 +284,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] { ("staminaMax" | uint16L) :: ("stamina" | uint16L) :: ignore(147) :: - ("certs" | listOfN(uint8L, uint8L)) :: + ("certs" | listOfN(uint8L, CertificationType.codec)) :: optional(bool, uint32L) :: //ask about sample CCRIDER ignore(4) :: (("implants" | PacketHelpers.listOfNSized(numberOfImplantSlots(bep), implant_entry_codec)) >>:~ { implants => diff --git a/common/src/main/scala/net/psforever/types/CertificationType.scala b/common/src/main/scala/net/psforever/types/CertificationType.scala new file mode 100644 index 000000000..d06e2d198 --- /dev/null +++ b/common/src/main/scala/net/psforever/types/CertificationType.scala @@ -0,0 +1,79 @@ +// Copyright (c) 2017 PSForever +package net.psforever.types + +import net.psforever.packet.PacketHelpers +import scodec.codecs._ +/** + * An `Enumeration` of the available certifications.
+ *
+ * As indicated, the following certifications are always enqueued on an avatar's permissions: + * `StandardAssault`, `StandardExoSuit`, `AgileExoSuit`. + * They must still be included in any formal lists of permitted equipment for a user. + * The other noted certifications require all prerequisite certifications listed or they themselves will not be listed: + * `ElectronicsExpert` and `AdvancedEngineering`. + * No other certification requires its prerequisites explicitly listed to be listed itself. + * Any certification that contains multiple other certifications overrides those individual certifications in the list. + * There is no certification for the Advanced Nanite Transport.
+ *
+ * In terms of pricing, `StandardAssault`, `StandardExoSuit`, and `AgileExoSuit` are costless. + * A certification that contains multiple other certifications acts as the overriding cost. + * (Taking `UniMAX` while owning `AAMAX` will refund the `AAMAX` cost and replace it with the `UniMAX` cost.) + */ +object CertificationType extends Enumeration { + type Type = Value + val + //0 + StandardAssault, //always listed + MediumAssault, + HeavyAssault, + SpecialAssault, + AntiVehicular, + Sniping, + EliteAssault, + AirCalvaryScout, + AirCalvaryInterceptor, + AirCalvaryAssault, + //10 + AirSupport, + ATV, + LightScout, + AssaultBuggy, + ArmoredAssault1, + ArmoredAssault2, + GroundTransport, + GroundSupport, + BattleFrameRobotics, + Flail, + //20 + Switchblade, + Harasser, + Phantasm, + GalaxyGunship, + BFRAntiAircraft, + BFRAntiInfantry, + StandardExoSuit, //always listed + AgileExoSuit, //always listed + ReinforcedExoSuit, + InfiltrationSuit, + //30 + AAMAX, + AIMAX, + AVMAX, + UniMAX, + Medical, + AdvancedMedical, + Hacking, + AdvancedHacking, + ExpertHacking, + DataCorruption, + //40 + ElectronicsExpert, //requires Hacking and AdvancedHacking + Engineering, + CombatEngineering, + FortificationEngineering, + AssaultEngineering, + AdvancedEngineering //requires Engineering and CombatEngineering + = Value + + implicit val codec = PacketHelpers.createEnumerationCodec(this, uint8L) +} diff --git a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala index d585e60af..f61635200 100644 --- a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala +++ b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala @@ -206,6 +206,8 @@ class ObjectCreateDetailedMessageTest extends Specification { char.appearance.ribbons.middle mustEqual MeritCommendation.None char.appearance.ribbons.lower mustEqual MeritCommendation.None char.appearance.ribbons.tos mustEqual MeritCommendation.None + char.bep mustEqual 0 + char.cep mustEqual 0 char.healthMax mustEqual 100 char.health mustEqual 100 char.armor mustEqual 50 //standard exosuit value @@ -214,7 +216,15 @@ class ObjectCreateDetailedMessageTest extends Specification { char.unk3 mustEqual 7 char.staminaMax mustEqual 100 char.stamina mustEqual 100 - char.certs mustEqual List(0, 1, 11, 21, 26, 27, 28) + char.certs.length mustEqual 7 + char.certs.head mustEqual CertificationType.StandardAssault + char.certs(1) mustEqual CertificationType.MediumAssault + char.certs(2) mustEqual CertificationType.ATV + char.certs(3) mustEqual CertificationType.Harasser + char.certs(4) mustEqual CertificationType.StandardExoSuit + char.certs(5) mustEqual CertificationType.AgileExoSuit + char.certs(6) mustEqual CertificationType.ReinforcedExoSuit + char.implants.length mustEqual 0 char.firstTimeEvents.size mustEqual 4 char.firstTimeEvents.head mustEqual "xpe_sanctuary_help" char.firstTimeEvents(1) mustEqual "xpe_th_firemodes" @@ -406,11 +416,19 @@ class ObjectCreateDetailedMessageTest extends Specification { 50, 1, 7, 7, 100, 100, - List(0, 1, 11, 21, 26, 27, 28), + List( + CertificationType.StandardAssault, + CertificationType.MediumAssault, + CertificationType.ATV, + CertificationType.Harasser, + CertificationType.StandardExoSuit, + CertificationType.AgileExoSuit, + CertificationType.ReinforcedExoSuit + ), List(), "xpe_sanctuary_help" :: "xpe_th_firemodes" :: "used_beamer" :: "map13" :: Nil, List.empty, - InventoryData(inv), + Some(InventoryData(inv)), DrawnSlot.Pistol1 ) val msg = ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj) diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 8013b820c..56e0024d3 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -394,8 +394,8 @@ class WorldSessionActor extends Actor with MDCContextAware { case ListAccountCharacters => val gen : AtomicInteger = new AtomicInteger(1) - log.info(s"${PacketCoding.DecodePacket(objectHex)}") - sendRawResponse(objectHex) + //log.info(s"${PacketCoding.DecodePacket(objectHex)}") + sendResponse(objectHex) sendResponse(PacketCoding.CreateGamePacket(0, CharacterInfoMessage(15,PlanetSideZoneID(10000), 41605313, PlanetSideGUID(75), false, 6404428))) //load characters // SetCharacterSelectScreenGUID(player, gen) @@ -456,7 +456,7 @@ class WorldSessionActor extends Actor with MDCContextAware { // sendResponse(PacketCoding.CreateGamePacket(0, // ObjectCreateDetailedMessage(ObjectClass.avatar, tplayer.GUID, tplayer.Definition.Packet.DetailedConstructorData(tplayer).get) // )) - sendRawResponse(objectHex) + sendResponse(objectHex) avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.LoadPlayer(tplayer.GUID, tplayer.Definition.Packet.ConstructorData(tplayer).get)) log.debug(s"ObjectCreateDetailedMessage: ${tplayer.Definition.Packet.DetailedConstructorData(tplayer).get}") @@ -495,47 +495,53 @@ class WorldSessionActor extends Actor with MDCContextAware { failWithError(s"Invalid packet class received: $default") } - val objectHex = hex"18 4a c7 00 00 bc 84 B0 0c 0b 95 59 9a 84 40 b0 00 01 32 00 00 08 70 43 00 43 00 52 00 49 00 44 00 45 00 52 00 82 28 c9 3d 04 40 03 c0 01 40 02 80 00 40 35 18 40 00 25 40 42 00 6c 00 61 00 63 00 6b 00 20 00 41 00 72 00 6d 00 6f 00 72 00 65 00 64 00 20 00 52 00 65 00 61 00 70 00 65 00 72 00 73 00 0f 00 00 03 02 0c 00 00 03 88 00 00 00 d4 00 00 01 9c 04 00 00 09 19 90 02 04 3c 28 00 00 00 00 00 00 00 00 00 00 00 00 01 90 01 90 00 64 00 00 01 00 7e c8 00 c8 00 00 01 b9 53 4c 00 00 00 00 00 00 00 00 00 00 00 00 00 03 40 00 40 81 c6 86 c8 48 88 c9 09 49 8a 67 86 e0 00 01 25 e0 32 d8 09 6c 00 00 3c 04 00 02 30 7870655f626c61636b6f7073917870655f626174746c655f72616e6b5f39927870655f626174746c655f72616e6b5f3233927870655f636f6d6d616e645f72616e6b5f318f7870655f666f726d5f6f75746669748e7870655f6d61696c5f616c657274927870655f626174746c655f72616e6b5f3232927870655f636f6d6d616e645f72616e6b5f33907870655f666f726d5f706c61746f6f6e927870655f626174746c655f72616e6b5f3133927870655f626174746c655f72616e6b5f3132927870655f626174746c655f72616e6b5f3130927870655f626174746c655f72616e6b5f3134927870655f626174746c655f72616e6b5f3135917870655f626174746c655f72616e6b5f38927870655f626174746c655f72616e6b5f3131927870655f626174746c655f72616e6b5f3231927870655f626174746c655f72616e6b5f3230927870655f626174746c655f72616e6b5f3138927870655f626174746c655f72616e6b5f3139907870655f6a6f696e5f706c61746f6f6e927870655f626174746c655f72616e6b5f3137927870655f626174746c655f72616e6b5f31368f7870655f6a6f696e5f6f7574666974927870655f626174746c655f72616e6b5f3235927870655f626174746c655f72616e6b5f3234917870655f626174746c655f72616e6b5f37917870655f62696e645f666163696c6974798c7870655f62696e645f616d73927870655f636f6d6d616e645f72616e6b5f35927870655f636f6d6d616e645f72616e6b5f32927870655f696e7374616e745f616374696f6e8e7870655f666f726d5f7371756164917870655f626174746c655f72616e6b5f34937870655f776172705f676174655f7573616765917870655f626174746c655f72616e6b5f32917870655f626174746c655f72616e6b5f33927870655f73616e6374756172795f68656c708c7870655f64726f705f706f64937870655f6f72626974616c5f73687574746c65917870655f626174746c655f72616e6b5f368e7870655f6a6f696e5f7371756164917870655f626174746c655f72616e6b5f35927870655f74685f737769746368626c6164658d7870655f74685f726f757465728c7870655f74685f666c61696c8a7870655f74685f616e748a7870655f74685f616d738a7870655f74685f62667289757365645f6f69637791757365645f616476616e6365645f61636597766973697465645f73706974666972655f74757272657498766973697465645f73706974666972655f636c6f616b656493766973697465645f73706974666972655f616192766973697465645f74616e6b5f7472617073a1766973697465645f706f727461626c655f6d616e6e65645f7475727265745f6e638e757365645f6d616763757474657293766973697465645f77616c6c5f7475727265748b766973697465645f616d738b766973697465645f616e7490766973697465645f64726f707368697091766973697465645f6c6962657261746f7294766973697465645f6c6967687467756e7368697091766973697465645f6c696768746e696e6790766973697465645f6d616772696465728f766973697465645f70726f776c657293766973697465645f71756164737465616c746890766973697465645f736b7967756172649a766973697465645f74687265656d616e686561767962756767799d766973697465645f74776f5f6d616e5f61737361756c745f627567677998766973697465645f74776f6d616e6865617679627567677998766973697465645f74776f6d616e686f766572627567677990766973697465645f76616e67756172648d766973697465645f666c61696c8e766973697465645f726f7574657293766973697465645f737769746368626c6164658e766973697465645f6175726f726193766973697465645f626174746c657761676f6e8c766973697465645f6675727993766973697465645f7175616461737361756c7496766973697465645f67616c6178795f67756e736869708e766973697465645f6170635f74728e766973697465645f6170635f767390766973697465645f6c6f64657374617290766973697465645f7068616e7461736d91766973697465645f7468756e64657265728e766973697465645f6170635f6e638f766973697465645f76756c747572658c766973697465645f7761737090766973697465645f6d6f73717569746f97766973697465645f617068656c696f6e5f666c6967687497766973697465645f617068656c696f6e5f67756e6e657297766973697465645f636f6c6f737375735f666c6967687497766973697465645f636f6c6f737375735f67756e6e657298766973697465645f706572656772696e655f666c6967687498766973697465645f706572656772696e655f67756e6e657289757365645f62616e6b95766973697465645f7265736f757263655f73696c6f9e766973697465645f63657274696669636174696f6e5f7465726d696e616c94766973697465645f6d65645f7465726d696e616c93757365645f6e616e6f5f64697370656e73657295766973697465645f73656e736f725f736869656c649a766973697465645f62726f6164636173745f77617270676174658c757365645f7068616c616e7894757365645f7068616c616e785f6176636f6d626f96757365645f7068616c616e785f666c616b636f6d626f96766973697465645f77617270676174655f736d616c6c91757365645f666c616d657468726f7765729a757365645f616e6369656e745f7475727265745f776561706f6e92766973697465645f4c4c555f736f636b657492757365645f656e657267795f67756e5f6e6397766973697465645f6d656469756d7472616e73706f72749f757365645f617068656c696f6e5f696d6d6f6c6174696f6e5f63616e6e6f6e93757365645f6772656e6164655f706c61736d6193757365645f6772656e6164655f6a616d6d657298766973697465645f736869656c645f67656e657261746f7295766973697465645f6d6f74696f6e5f73656e736f7296766973697465645f6865616c74685f6372797374616c96766973697465645f7265706169725f6372797374616c97766973697465645f76656869636c655f6372797374616c91757365645f6772656e6164655f6672616788757365645f61636598766973697465645f6164765f6d65645f7465726d696e616c8b757365645f6265616d657290757365645f626f6c745f6472697665728b757365645f6379636c65728a757365645f676175737391757365645f68756e7465727365656b657288757365645f6973708b757365645f6c616e6365728b757365645f6c61736865728e757365645f6d61656c7374726f6d8c757365645f70686f656e69788b757365645f70756c7361728d757365645f70756e69736865728e757365645f725f73686f7467756e8d757365645f7261646961746f7288757365645f72656b8d757365645f72657065617465728c757365645f726f636b6c65748c757365645f737472696b65728f757365645f73757070726573736f728c757365645f7468756d7065729c766973697465645f76616e755f636f6e74726f6c5f636f6e736f6c6598766973697465645f636170747572655f7465726d696e616c92757365645f6d696e695f636861696e67756e91757365645f6c617a655f706f696e7465728c757365645f74656c657061648b757365645f7370696b657291757365645f68656176795f736e6970657293757365645f636f6d6d616e645f75706c696e6b8d757365645f66697265626972648e757365645f666c6563686574746594757365645f68656176795f7261696c5f6265616d89757365645f696c63399a766973697465645f67656e657261746f725f7465726d696e616c8e766973697465645f6c6f636b65729a766973697465645f65787465726e616c5f646f6f725f6c6f636b9c766973697465645f6169725f76656869636c655f7465726d696e616c97766973697465645f67616c6178795f7465726d696e616c98766973697465645f696d706c616e745f7465726d696e616c99766973697465645f7365636f6e646172795f6361707475726590757365645f32356d6d5f63616e6e6f6e99757365645f6c6962657261746f725f626f6d6261726469657293766973697465645f7265706169725f73696c6f93766973697465645f76616e755f6d6f64756c6591757365645f666c61696c5f776561706f6e8b757365645f73637974686598766973697465645f7265737061776e5f7465726d696e616c8c757365645f62616c6c67756e95757365645f616e6e69766572736172795f67756e6195757365645f616e6e69766572736172795f67756e6294757365645f616e6e69766572736172795f67756e90757365645f37356d6d5f63616e6e6f6e92757365645f6170635f6e635f776561706f6e92757365645f6170635f74725f776561706f6e92757365645f6170635f76735f776561706f6e90757365645f666c75785f63616e6e6f6e93757365645f617068656c696f6e5f6c617365729f757365645f617068656c696f6e5f706c61736d615f726f636b65745f706f6491757365645f617068656c696f6e5f70706196757365645f617068656c696f6e5f73746172666972658c757365645f666c7578706f6494766973697465645f6266725f7465726d696e616c95757365645f636f6c6f737375735f6275727374657296757365645f636f6c6f737375735f636861696e67756e9e757365645f636f6c6f737375735f636c75737465725f626f6d625f706f64a0757365645f636f6c6f737375735f6475616c5f3130306d6d5f63616e6e6f6e7399757365645f636f6c6f737375735f74616e6b5f63616e6e6f6e96766973697465645f64616d6167655f6372797374616c96766973697465645f656e657267795f6372797374616c9b757365645f68656176795f6772656e6164655f6c61756e6368657298757365645f33356d6d5f726f74617279636861696e67756e8b757365645f6b6174616e6190757365645f33356d6d5f63616e6e6f6e93757365645f7265617665725f776561706f6e7396757365645f6c696768746e696e675f776561706f6e738c757365645f6d65645f61707090757365645f32306d6d5f63616e6e6f6e98766973697465645f6d6f6e6f6c6974685f616d657269736899766973697465645f6d6f6e6f6c6974685f636572797368656e97766973697465645f6d6f6e6f6c6974685f637973736f7297766973697465645f6d6f6e6f6c6974685f6573616d697299766973697465645f6d6f6e6f6c6974685f666f72736572616c97766973697465645f6d6f6e6f6c6974685f686f7373696e99766973697465645f6d6f6e6f6c6974685f697368756e64617298766973697465645f6d6f6e6f6c6974685f7365617268757397766973697465645f6d6f6e6f6c6974685f736f6c73617292757365645f6e635f6865765f66616c636f6e99757365645f6e635f6865765f7363617474657263616e6e6f6e93757365645f6e635f6865765f73706172726f7791757365645f61726d6f725f736970686f6e9f757365645f706572656772696e655f6475616c5f6d616368696e655f67756e9f757365645f706572656772696e655f6475616c5f726f636b65745f706f647399757365645f706572656772696e655f6d65636868616d6d65728f757365645f6e74755f736970686f6e9e757365645f706572656772696e655f7061727469636c655f63616e6e6f6e96757365645f706572656772696e655f73706172726f7791757365645f3130356d6d5f63616e6e6f6e92757365645f31356d6d5f636861696e67756ea0757365645f70756c7365645f7061727469636c655f616363656c657261746f7293757365645f726f74617279636861696e67756e9f766973697465645f6465636f6e737472756374696f6e5f7465726d696e616c95757365645f736b7967756172645f776561706f6e7391766973697465645f67656e657261746f7291757365645f67617573735f63616e6e6f6e89757365645f7472656b95757365645f76616e67756172645f776561706f6e73a4766973697465645f616e6369656e745f6169725f76656869636c655f7465726d696e616ca2766973697465645f616e6369656e745f65717569706d656e745f7465726d696e616c96766973697465645f6f726465725f7465726d696e616ca7766973697465645f616e6369656e745f67726f756e645f76656869636c655f7465726d696e616c9f766973697465645f67726f756e645f76656869636c655f7465726d696e616c97757365645f76756c747572655f626f6d6261726469657298757365645f76756c747572655f6e6f73655f63616e6e6f6e98757365645f76756c747572655f7461696c5f63616e6e6f6e97757365645f776173705f776561706f6e5f73797374656d91766973697465645f636861726c6965303591766973697465645f636861726c6965303691766973697465645f636861726c6965303791766973697465645f636861726c6965303891766973697465645f636861726c696530398e766973697465645f736c656430348e766973697465645f736c656430358e766973697465645f736c656430368e766973697465645f736c656430378e766973697465645f736c65643038857567643036857567643035857567643034857567643033857567643032857567643031856d61703939856d61703938856d61703937856d61703936856d61703135856d61703134856d61703133856d61703132856d61703131856d61703034856d61703035856d61703033856d61703031856d61703036856d61703032856d61703039856d61703037856d617031300800000092747261696e696e675f776561706f6e73303192747261696e696e675f7761727067617465738c747261696e696e675f6d617092747261696e696e675f696e76656e746f727990747261696e696e675f6865616c696e678d747261696e696e675f686172748f747261696e696e675f61726d6f727390747261696e696e675f77656c636f6d650000000000000000000000000000000000000000ab000480000005000000058000000800000008800000090000000f0000000f8000001000000012800000130000001a0000001a8000001c800000228000002e00000031800000320000003580000036000000368000003700000039000000398000003a0000003a8000003b0000003f800000400000004080000041000000418000004e000000518000005580000059000000598000005a0000005a800000610000006180000063000000648000006b8000006c0000006c8000006f0000006f800000700000007080000071000000718000007280000073000000798000007a0000000080800004808000050080000a8080000b0080000d8080000e0080000e8080000f0080001080800011008000140080001c808000270080002a8080002b00800033808000388080003c0080003c8080004000800043808000440080004480800045008000470080004c0080004f808000520080005400800000002f0a26c9313c024000001000060279a272780c80000100026b271682480000020000c041c0464f019000006400d43541d08900000040001808388946a0320000008019041c821700000008046ce915631018000000400018083822c6a030000019001d2338421b00000008000301070438ac060000032003a4630c466000000100006020e06c1e80c000006400748e01c92c00000020000c041c11e4101800000c800e90a02331800000040001808381b06e030000019001989ec436b000000080003010c81d924060000019003310e87f0600000010000602190d31780c000003200662fa22e6c00000020000c04320a82f018000006400e90683bd9800000040001808381205a030000019000205808bcb000001900040e4908058e0000032006629c1d00b4c00000020000c043209c35018000006400cc480320175800000040001808642084a03000000c80198880540303000000080003010c87d86c060000019000b17e9100636000000100006020e01f2080c00000c800081580f010bc000006400414961a022f800000040001808de0004603000003200082818840477000000080003011bc0a11406000006400040a28680b2e000003200569271a017ac00000020000c041037435018000008c00ce2e04003498000000400018099e6c46e03000004b0019c4483406b70000000800030133cc28ec06000009600040ad8e80dfe0000032006710e1201fec00000020000c04cf2a837018000025800ce37432040f8000000400018099e7586a03000004b00058b18480843000000080003010702f11406000006400040f690010ce0000032000e0222786c8000064001c1d82b13900000c800380205233200001900074559050e40000320079afa0fa4c800002000d84b64f4e9000000400010300380" -// val objectHex = PacketCoding.CreateGamePacket(0, -// ObjectCreateDetailedMessage( -// 121, -// PlanetSideGUID(75), -// DetailedCharacterData( -// CharacterAppearanceData( -// PlacementData(Vector3(2931.5f,4404.6953f,45.0625f), Vector3(0.0f,0.0f,36.5625f)), -// BasicCharacterData("psemu2",PlanetSideEmpire.VS,CharacterGender.Male,20,3), -// 0, -// false, -// false, -// ExoSuitType.Standard, -// "", -// 15, -// false, -// 0.0f, 0.0f, -// false, -// GrenadeState.None, -// false, -// false, -// false, -// RibbonBars( -// MeritCommendation.None,MeritCommendation.None,MeritCommendation.None,MeritCommendation.None -// ) -// ), -// 31467, -// 0, -// 100, 100, -// 50, -// 1,7,7, -// 100,100, -// 7, -// CertificationEntries(List(0, 0, 11, 26, 27, 31, 41, 0, 0),Some(0)), -// List("xpe_blackops"), -// List(), -// None, -// DrawnSlot.None -// ) -// ) -// ) +// val objectHex = hex"18 57 0C 00 00 BC 84 B0 06 C2 D7 65 53 5C A1 60 00 01 34 40 00 09 70 49 00 6C 00 6C 00 6C 00 49 00 49 00 49 00 6C 00 6C 00 6C 00 49 00 6C 00 49 00 6C 00 6C 00 49 00 6C 00 6C 00 6C 00 49 00 6C 00 6C 00 49 00 84 52 70 76 1E 80 80 00 00 00 00 00 3F FF C0 00 00 00 20 00 00 0F F6 A7 03 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FD 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 90 01 90 00 64 00 00 01 00 7E C8 00 C8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 C0 00 42 C5 46 86 C7 00 00 00 80 00 00 12 40 78 70 65 5F 73 61 6E 63 74 75 61 72 79 5F 68 65 6C 70 90 78 70 65 5F 74 68 5F 66 69 72 65 6D 6F 64 65 73 8B 75 73 65 64 5F 62 65 61 6D 65 72 85 6D 61 70 31 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 0A 23 02 60 04 04 40 00 00 10 00 06 02 08 14 D0 08 0C 80 00 02 00 02 6B 4E 00 82 88 00 00 02 00 00 C0 41 C0 9E 01 01 90 00 00 64 00 44 2A 00 10 91 00 00 00 40 00 18 08 38 94 40 20 32 00 00 00 80 19 05 48 02 17 20 00 00 08 00 70 29 80 43 64 00 00 32 00 0E 05 40 08 9C 80 00 06 40 01 C0 AA 01 19 90 00 00 C8 00 3A 15 80 28 72 00 00 19 00 04 0A B8 05 26 40 00 03 20 06 C2 58 00 A7 88 00 00 02 00 00 80 00 00" + val objectHex = PacketCoding.CreateGamePacket(0, + ObjectCreateDetailedMessage( + 121, + PlanetSideGUID(75), + DetailedCharacterData( + CharacterAppearanceData( + PlacementData(Vector3(3674.8438f,2726.789f,91.15625f), Vector3(0.0f,0.0f,36.5625f)), + BasicCharacterData("psemu2",PlanetSideEmpire.VS,CharacterGender.Female,41,1), + 0, + false, + false, + ExoSuitType.Standard, + "", + 0, + false, + 2.8125f, 210.9375f, + true, + GrenadeState.None, + false, + false, + false, + RibbonBars() + ), + 0, + 0, + 100, 100, + 50, + 1,7,7, + 100,100, + List( + CertificationType.StandardAssault, + CertificationType.MediumAssault, + CertificationType.ATV, + CertificationType.Harasser, + CertificationType.StandardExoSuit, + CertificationType.AgileExoSuit, + CertificationType.ReinforcedExoSuit + ), + List(), + List("xpe_blackops"), + List(), + None, + DrawnSlot.None + ) + ) + ) def handlePkt(pkt : PlanetSidePacket) : Unit = pkt match { case ctrl : PlanetSideControlPacket =>