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 b15d26947..24e802636 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 @@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter import net.psforever.objects.{EquipmentSlot, Player} import net.psforever.objects.equipment.Equipment import net.psforever.packet.game.objectcreate._ -import net.psforever.types.{GrenadeState, ImplantType} +import net.psforever.types.{ExoSuitType, GrenadeState, ImplantType} import scala.annotation.tailrec import scala.util.{Success, Try} @@ -124,7 +124,8 @@ object AvatarConverter { } def MakeDetailedCharacterData(obj : Player) : (Option[Int])=>DetailedCharacterData = { - val bep = obj.BEP + val bep : Long = obj.BEP + val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None } val ba : DetailedCharacterA = DetailedCharacterA( bep, obj.CEP, @@ -134,6 +135,7 @@ object AvatarConverter { obj.Armor, 0L, obj.MaxStamina, obj.Stamina, + maxOpt, 0, 0, 0L, List(0, 0, 0, 0, 0, 0), obj.Certifications.toList.sortBy(_.id) //TODO is sorting necessary? diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala index 8930da40a..9812e6a68 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala @@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter import net.psforever.objects.{EquipmentSlot, Player} import net.psforever.objects.equipment.Equipment import net.psforever.packet.game.objectcreate._ -import net.psforever.types.{CertificationType, CharacterVoice, GrenadeState, ImplantType} +import net.psforever.types._ import scala.annotation.tailrec import scala.util.{Failure, Success, Try} @@ -77,7 +77,8 @@ class CharacterSelectConverter extends AvatarConverter { } private def MakeDetailedCharacterData(obj : Player) : (Option[Int]=>DetailedCharacterData) = { - val bep = obj.BEP + val bep : Long = obj.BEP + val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None } val ba : DetailedCharacterA = DetailedCharacterA( bep, obj.CEP, @@ -87,6 +88,7 @@ class CharacterSelectConverter extends AvatarConverter { 0, 0L, 1, 1, + maxOpt, 0, 0, 0L, List(0, 0, 0, 0, 0, 0), certs = List.empty[CertificationType.Value] diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala index 7993d51e3..e108fc22d 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala @@ -72,6 +72,7 @@ class CorpseConverter extends AvatarConverter { } private def MakeDetailedCharacterData(obj : Player) : (Option[Int]=>DetailedCharacterData) = { + val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None } val ba : DetailedCharacterA = DetailedCharacterA( bep = 0L, cep = 0L, @@ -81,6 +82,7 @@ class CorpseConverter extends AvatarConverter { 0, 0L, 0, 0, + maxOpt, 0, 0, 0L, List(0, 0, 0, 0, 0, 0), certs = List.empty[CertificationType.Value] diff --git a/common/src/main/scala/net/psforever/objects/zones/Zone.scala b/common/src/main/scala/net/psforever/objects/zones/Zone.scala index 4cb2f77c4..c92705579 100644 --- a/common/src/main/scala/net/psforever/objects/zones/Zone.scala +++ b/common/src/main/scala/net/psforever/objects/zones/Zone.scala @@ -6,6 +6,7 @@ import akka.routing.RandomPool import net.psforever.objects.ballistics.Projectile import net.psforever.objects._ import net.psforever.objects.ce.Deployable +import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.equipment.Equipment import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.guid.actor.UniqueNumberSystem @@ -313,6 +314,7 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) { private def BuildSupportObjects() : Unit = { //guard against errors here, but don't worry about specifics; let ZoneActor.ZoneSetupCheck complain about problems + val other : ListBuffer[IdentifiableEntity] = new ListBuffer[IdentifiableEntity]() //turret to weapon Map.TurretToWeapon.foreach({ case ((turret_guid, weapon_guid)) => ((GUID(turret_guid) match { @@ -333,11 +335,13 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) { }) match { case Some((obj, Some(weapon : Tool))) => guid.register(weapon, weapon_guid) - weapon.AmmoSlots.foreach(slot => guid.register(slot.Box, "dynamic")) - obj.Inventory.Items.foreach(item => guid.register(item.obj, "dynamic")) //internal ammunition reserves, if any + other ++= weapon.AmmoSlots.map(slot => slot.Box) + other ++= obj.Inventory.Items.map(item => item.obj) //internal ammunition reserves, if any case _ => ; } }) + //after all fixed GUID's are defined ... + other.foreach(obj => guid.register(obj, "dynamic")) } private def MakeBuildings(implicit context : ActorContext) : PairMap[Int, Building] = { 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 7d86cc58b..141dd109a 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.{CertificationType, ImplantType} +import net.psforever.types.{CertificationType, ExoSuitType, ImplantType} import scodec.{Attempt, Codec} import scodec.codecs._ import shapeless.{::, HNil} @@ -71,6 +71,8 @@ final case class DCDExtra2(unk1 : Int, * range is 0-65535 * @param stamina for `x / y` of stamina points, this is the avatar's `x` value; * range is 0-65535 + * @param max_field unk; + * this field exists only when the player is wearing a mechanized assault exo-suit * @param certs the `List` of certifications */ final case class DetailedCharacterA(bep : Long, @@ -85,14 +87,16 @@ final case class DetailedCharacterA(bep : Long, unk5 : Long, staminaMax : Int, stamina : Int, + max_field : Option[Long], unk6 : Int, unk7 : Int, unk8 : Long, unk9 : List[Int], certs : List[CertificationType.Value]) extends StreamBitSize { override def bitsize : Long = { + val maxFieldSize = max_field match { case Some(_) => 32L ; case None => 0L } val certSize : Long = certs.length * 8 - 428L + certSize + 428L + maxFieldSize + certSize } } @@ -197,6 +201,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] { armor : Int, staminaMax : Int, stamina : Int, + maxField : Option[Long], certs : List[CertificationType.Value], implants : List[ImplantEntry], firstTimeEvents : List[String], @@ -213,6 +218,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] { armor, 0L, staminaMax, stamina, + maxField, 0, 0, 0L, @@ -527,7 +533,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] { */ def isBR24(bep : Long) : Boolean = bep > 2286230 - val a_codec : Codec[DetailedCharacterA] = ( + def a_codec(suit : ExoSuitType.Value) : Codec[DetailedCharacterA] = ( ("bep" | uint32L) :: ("cep" | uint32L) :: ("unk1" | uint32L) :: @@ -540,7 +546,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] { ("unk5" | uint32) :: //endianness? ("staminaMax" | uint16L) :: ("stamina" | uint16L) :: - conditional(false, uint32L) :: //see ps.c: sub_901150, line#1070692 + conditional(suit == ExoSuitType.MAX, uint32L) :: ("unk6" | uint16L) :: ("unk7" | uint(3)) :: ("unk8" | uint32L) :: @@ -548,13 +554,13 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] { ("certs" | listOfN(uint8L, CertificationType.codec)) ).exmap[DetailedCharacterA] ( { - case bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: None :: u6 :: u7 :: u8 :: u9 :: certs :: HNil => - Attempt.successful(DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, u6, u7, u8, u9, certs)) + case bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: max :: u6 :: u7 :: u8 :: u9 :: certs :: HNil => + Attempt.successful(DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, max, u6, u7, u8, u9, certs)) }, { - case DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, u6, u7, u8, u9, certs) => + case DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, max, u6, u7, u8, u9, certs) => Attempt.successful( - bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: None :: u6 :: u7 :: u8 :: u9 :: certs :: HNil + bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: max :: u6 :: u7 :: u8 :: u9 :: certs :: HNil ) } ) @@ -614,8 +620,8 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] { } ) - def codec(pad_length : Option[Int]) : Codec[DetailedCharacterData] = ( - ("a" | a_codec) >>:~ { a => + def codec(suit : ExoSuitType.Value, pad_length : Option[Int]) : Codec[DetailedCharacterData] = ( + ("a" | a_codec(suit)) >>:~ { a => ("b" | b_codec(a.bep, pad_length)).hlist } ).exmap[DetailedCharacterData] ( @@ -629,5 +635,5 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] { } ) - implicit val codec : Codec[DetailedCharacterData] = codec(None) + implicit val codec : Codec[DetailedCharacterData] = codec(ExoSuitType.Standard, None) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala index 071674822..c4778dba3 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala @@ -114,7 +114,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] { def codec(position_defined : Boolean) : Codec[DetailedPlayerData] = ( conditional(position_defined, "pos" | PlacementData.codec) >>:~ { pos => ("basic_appearance" | CharacterAppearanceData.codec(PlayerData.PaddingOffset(pos))) >>:~ { app => - ("character_data" | DetailedCharacterData.codec(app.altModelBit)) :: + ("character_data" | DetailedCharacterData.codec(app.a.exosuit, app.altModelBit)) :: optional(bool, "inventory" | InventoryData.codec_detailed) :: ("drawn_slot" | DrawnSlot.codec) :: bool //usually false diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala index 34f8999d1..b611f048b 100644 --- a/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala +++ b/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala @@ -12,12 +12,37 @@ class DetailedCharacterDataTest extends Specification { val string = hex"18 570C0000 BC8 4B00 6C2D7 65535 CA16 0 00 01 34 40 00 0970 49006C006C006C004900490049006C006C006C0049006C0049006C006C0049006C006C006C0049006C006C004900 84 52 70 76 1E 80 80 00 00 00 00 00 3FFFC 0 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 FC 00 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 string_seated = hex"181f0c000066d5bc84b00808000012e049006c006c006c004900490049006c006c006c0049006c0049006c006c0049006c006c006c004900" ++ - hex"6c006c0049008452700000000000000000000000000000002000000fe6a703fffffffffffffffffffffffffffffffc000000000000000000" ++ - hex"00000000000000000000019001900064000001007ec800c80000000000000000000000000000000000000001c00042c54686c70000008000" ++ - hex"0012407870655f73616e6374756172795f68656c70907870655f74685f666972656d6f6465738b757365645f6265616d6572856d61703133" ++ - hex"0000000000000000000000000000000000000000000000000000000000010a2302600404400000100006020814d0080c80000200026b4e00" ++ - hex"82880000020000c041c09e01019000006400442a001091000000400018083894402032000000801905480217200000080070298043640000" ++ - hex"32000e0540089c8000064001c0aa0119900000c8003a1580287200001900040ab805264000032006c25800a7880000020000800000" + hex"6c006c0049008452700000000000000000000000000000002000000fe6a703fffffffffffffffffffffffffffffffc000000000000000000" ++ + hex"00000000000000000000019001900064000001007ec800c80000000000000000000000000000000000000001c00042c54686c70000008000" ++ + hex"0012407870655f73616e6374756172795f68656c70907870655f74685f666972656d6f6465738b757365645f6265616d6572856d61703133" ++ + hex"0000000000000000000000000000000000000000000000000000000000010a2302600404400000100006020814d0080c80000200026b4e00" ++ + hex"82880000020000c041c09e01019000006400442a001091000000400018083894402032000000801905480217200000080070298043640000" ++ + hex"32000e0540089c8000064001c0aa0119900000c8003a1580287200001900040ab805264000032006c25800a7880000020000800000" + val string_max = + hex"187d280000bc8010063cb74a247ad390000080400008a048006100480061004100540052004d00610078004a727bb69e808000000000003f" ++ + hex"ffc000000020000000400703ffffffffffffffffffffffffffffffff14ec000000000000000000000000000000000001e001e00102040001" ++ + hex"007ec800c800000000000000000000000000000000000000000000000140004686c840000600000012207870655f626174746c655f72616e" ++ + hex"6b5f33917870655f62696e645f666163696c697479927870655f696e7374616e745f616374696f6e917870655f626174746c655f72616e6b" ++ + hex"5f34917870655f626174746c655f72616e6b5f32927870655f73616e6374756172795f68656c708c7870655f64726f705f706f6493787065" ++ + hex"5f6f72626974616c5f73687574746c65917870655f626174746c655f72616e6b5f358e7870655f74685f6e6f6e73616e638f7870655f7468" ++ + hex"5f67726f756e645f708b7870655f74685f616d6d6f907870655f74685f666972656d6f6465738a7870655f74685f6d617897766973697465" ++ + hex"645f73706974666972655f74757272657493766973697465645f77616c6c5f74757272657495766973697465645f7265736f757263655f73" ++ + hex"696c6f9e766973697465645f63657274696669636174696f6e5f7465726d696e616c94766973697465645f6d65645f7465726d696e616c9a" ++ + hex"766973697465645f62726f6164636173745f77617270676174658c757365645f7068616c616e789c766973697465645f6169725f76656869" ++ + hex"636c655f7465726d696e616c94766973697465645f6266725f7465726d696e616c8b757365645f6379636c657297766973697465645f6761" ++ + hex"6c6178795f7465726d696e616c98766973697465645f696d706c616e745f7465726d696e616c9a766973697465645f65787465726e616c5f" ++ + hex"646f6f725f6c6f636b98766973697465645f7265737061776e5f7465726d696e616c8e766973697465645f6c6f636b657295766973697465" ++ + hex"645f6d6f74696f6e5f73656e736f7293757365645f6772656e6164655f706c61736d6188757365645f72656b8d757365645f726570656174" ++ + hex"65729f766973697465645f6465636f6e737472756374696f6e5f7465726d696e616c99766973697465645f7365636f6e646172795f636170" ++ + hex"747572658f757365645f73757070726573736f7292757365645f74726865765f6275727374657295757365645f74726865765f6475616c63" ++ + hex"79636c657292757365645f74726865765f706f756e64657298766973697465645f636170747572655f7465726d696e616c96766973697465" ++ + hex"645f6f726465725f7465726d696e616c9f766973697465645f67726f756e645f76656869636c655f7465726d696e616c856d61703132856d" ++ + hex"61703130856d61703039856d61703035856d61703033856d6170303200000000000000000000000000000000000000000000000000000000" ++ + hex"0001131e5810040040000010000606049030080c800019000092080103900003200012414020b20000640015e01802102000000800030107" ++ + hex"10380406400000100320840042e400000100049090086c80000480009214011590000190001242c023b20000320002486004964000064000" ++ + hex"490d00c6c80000c8000921c019590000190001243c033b20000320002488006964000064000c211000086c80000020018424000115900000" ++ + hex"04003084c00023b2000000800610a00004964000001000c2150000a6c8000002001842c00015590000004003085c0002bb2000000800610c" ++ + hex"000059640000010000" val string_br32 = hex"18 2c e0 00 00 bc 84 B0 00 0b ea 00 6c 7d f1 10 00 00 02 40 00 08 60 4b 00 69 00 43 00 6b 00 4a 00 72 00 02 31 3a cc 82 c0 00 00 00 00 00 00 00 00 3e df 42 00 20 00 0e 00 40 43 40 4c 04 00 02 e8 00 00 03 a8 00 00 01 9c 04 00 00 b8 99 84 00 0e 68 28 00 00 00 00 00 00 00 00 00 00 00 00 01 90 01 90 00 c8 00 00 01 00 7e c8 00 5c 00 00 01 29 c1 cc 80 00 00 00 00 00 00 00 00 00 00 00 00 03 c0 00 40 81 01 c4 45 46 86 c8 88 c9 09 4a 4a 80 50 0c 13 00 00 15 00 80 00 48 00 7870655f6f766572686561645f6d6170 8d7870655f776172705f676174658f7870655f666f726d5f6f75746669748c7870655f626c61636b6f7073927870655f636f6d6d616e645f72616e6b5f35927870655f636f6d6d616e645f72616e6b5f33927870655f73616e6374756172795f68656c70927870655f626174746c655f72616e6b5f3133927870655f626174746c655f72616e6b5f3132927870655f626174746c655f72616e6b5f3130927870655f626174746c655f72616e6b5f3134927870655f626174746c655f72616e6b5f3135937870655f6f72626974616c5f73687574746c658c7870655f64726f705f706f64917870655f62696e645f666163696c697479917870655f626174746c655f72616e6b5f33917870655f626174746c655f72616e6b5f35917870655f626174746c655f72616e6b5f348e7870655f6a6f696e5f73717561648e7870655f666f726d5f7371756164927870655f696e7374616e745f616374696f6e917870655f626174746c655f72616e6b5f32937870655f776172705f676174655f7573616765917870655f626174746c655f72616e6b5f38927870655f626174746c655f72616e6b5f3131917870655f626174746c655f72616e6b5f368e7870655f6d61696c5f616c657274927870655f636f6d6d616e645f72616e6b5f31927870655f626174746c655f72616e6b5f3230927870655f626174746c655f72616e6b5f3138927870655f626174746c655f72616e6b5f3139907870655f6a6f696e5f706c61746f6f6e927870655f626174746c655f72616e6b5f3137927870655f626174746c655f72616e6b5f31368f7870655f6a6f696e5f6f7574666974927870655f626174746c655f72616e6b5f3235927870655f626174746c655f72616e6b5f3234927870655f636f6d6d616e645f72616e6b5f34907870655f666f726d5f706c61746f6f6e8c7870655f62696e645f616d73917870655f626174746c655f72616e6b5f39917870655f626174746c655f72616e6b5f378d7870655f74685f726f757465728c7870655f74685f666c61696c8a7870655f74685f616e748a7870655f74685f616d738f7870655f74685f67726f756e645f708c7870655f74685f6169725f708c7870655f74685f686f7665728d7870655f74685f67726f756e648a7870655f74685f626672927870655f74685f61667465726275726e65728a7870655f74685f6169728c7870655f74685f636c6f616b89757365645f6f69637791757365645f616476616e6365645f61636597766973697465645f73706974666972655f74757272657498766973697465645f73706974666972655f636c6f616b656493766973697465645f73706974666972655f616192766973697465645f74616e6b5f7472617073a1766973697465645f706f727461626c655f6d616e6e65645f7475727265745f6e63a1766973697465645f706f727461626c655f6d616e6e65645f7475727265745f74728e757365645f6d61676375747465728f757365645f636861696e626c6164658f757365645f666f726365626c61646593766973697465645f77616c6c5f74757272657498766973697465645f616e6369656e745f7465726d696e616c8b766973697465645f616d738b766973697465645f616e7490766973697465645f64726f707368697091766973697465645f6c6962657261746f7294766973697465645f6c6967687467756e7368697091766973697465645f6c696768746e696e6790766973697465645f6d616772696465728f766973697465645f70726f776c657293766973697465645f71756164737465616c746890766973697465645f736b7967756172649a766973697465645f74687265656d616e686561767962756767799d766973697465645f74776f5f6d616e5f61737361756c745f627567677998766973697465645f74776f6d616e6865617679627567677998766973697465645f74776f6d616e686f766572627567677990766973697465645f76616e67756172648d766973697465645f666c61696c8e766973697465645f726f7574657293766973697465645f737769746368626c6164658e766973697465645f6175726f726193766973697465645f626174746c657761676f6e8c766973697465645f6675727993766973697465645f7175616461737361756c7496766973697465645f67616c6178795f67756e736869708e766973697465645f6170635f74728e766973697465645f6170635f767390766973697465645f6c6f64657374617290766973697465645f7068616e7461736d91766973697465645f7468756e64657265728e766973697465645f6170635f6e638f766973697465645f76756c747572658c766973697465645f7761737090766973697465645f6d6f73717569746f97766973697465645f617068656c696f6e5f666c6967687497766973697465645f617068656c696f6e5f67756e6e657297766973697465645f636f6c6f737375735f666c6967687497766973697465645f636f6c6f737375735f67756e6e657298766973697465645f706572656772696e655f666c6967687498766973697465645f706572656772696e655f67756e6e657289757365645f62616e6b95766973697465645f7265736f757263655f73696c6f9e766973697465645f63657274696669636174696f6e5f7465726d696e616c94766973697465645f6d65645f7465726d696e616c93757365645f6e616e6f5f64697370656e73657295766973697465645f73656e736f725f736869656c649a766973697465645f62726f6164636173745f77617270676174658c757365645f7068616c616e7894757365645f7068616c616e785f6176636f6d626f96757365645f7068616c616e785f666c616b636f6d626f96766973697465645f77617270676174655f736d616c6c91757365645f666c616d657468726f7765729a757365645f616e6369656e745f7475727265745f776561706f6e92766973697465645f4c4c555f736f636b657492757365645f656e657267795f67756e5f6e6397766973697465645f6d656469756d7472616e73706f72749f757365645f617068656c696f6e5f696d6d6f6c6174696f6e5f63616e6e6f6e93757365645f6772656e6164655f706c61736d6193757365645f6772656e6164655f6a616d6d657298766973697465645f736869656c645f67656e657261746f7295766973697465645f6d6f74696f6e5f73656e736f7296766973697465645f6865616c74685f6372797374616c96766973697465645f7265706169725f6372797374616c97766973697465645f76656869636c655f6372797374616c91757365645f6772656e6164655f6672616788757365645f61636598766973697465645f6164765f6d65645f7465726d696e616c8b757365645f6265616d657290757365645f626f6c745f6472697665728b757365645f6379636c65728a757365645f676175737391757365645f68756e7465727365656b657288757365645f6973708b757365645f6c616e6365728b757365645f6c61736865728e757365645f6d61656c7374726f6d8c757365645f70686f656e69788b757365645f70756c7361728d757365645f70756e69736865728e757365645f725f73686f7467756e8d757365645f7261646961746f7288757365645f72656b8d757365645f72657065617465728c757365645f726f636b6c65748c757365645f737472696b65728f757365645f73757070726573736f728c757365645f7468756d7065729c766973697465645f76616e755f636f6e74726f6c5f636f6e736f6c6598766973697465645f636170747572655f7465726d696e616c92757365645f6d696e695f636861696e67756e91757365645f6c617a655f706f696e7465728c757365645f74656c657061648b757365645f7370696b657291757365645f68656176795f736e6970657293757365645f636f6d6d616e645f75706c696e6b8d757365645f66697265626972648e757365645f666c6563686574746594757365645f68656176795f7261696c5f6265616d89757365645f696c63399a766973697465645f67656e657261746f725f7465726d696e616c8e766973697465645f6c6f636b65729a766973697465645f65787465726e616c5f646f6f725f6c6f636b9c766973697465645f6169725f76656869636c655f7465726d696e616c97766973697465645f67616c6178795f7465726d696e616c98766973697465645f696d706c616e745f7465726d696e616c99766973697465645f7365636f6e646172795f6361707475726590757365645f32356d6d5f63616e6e6f6e99757365645f6c6962657261746f725f626f6d6261726469657293766973697465645f7265706169725f73696c6f93766973697465645f76616e755f6d6f64756c6591757365645f666c61696c5f776561706f6e8b757365645f73637974686598766973697465645f7265737061776e5f7465726d696e616c8c757365645f62616c6c67756e92757365645f656e657267795f67756e5f747295757365645f616e6e69766572736172795f67756e6195757365645f616e6e69766572736172795f67756e6294757365645f616e6e69766572736172795f67756e90757365645f37356d6d5f63616e6e6f6e92757365645f6170635f6e635f776561706f6e92757365645f6170635f74725f776561706f6e92757365645f6170635f76735f776561706f6e90757365645f666c75785f63616e6e6f6e9f757365645f617068656c696f6e5f706c61736d615f726f636b65745f706f6491757365645f617068656c696f6e5f7070618c757365645f666c7578706f6494766973697465645f6266725f7465726d696e616c9e757365645f636f6c6f737375735f636c75737465725f626f6d625f706f64a0757365645f636f6c6f737375735f6475616c5f3130306d6d5f63616e6e6f6e7399757365645f636f6c6f737375735f74616e6b5f63616e6e6f6e96766973697465645f656e657267795f6372797374616c9b757365645f68656176795f6772656e6164655f6c61756e6368657298757365645f33356d6d5f726f74617279636861696e67756e8b757365645f6b6174616e6190757365645f33356d6d5f63616e6e6f6e93757365645f7265617665725f776561706f6e7396757365645f6c696768746e696e675f776561706f6e738c757365645f6d65645f61707090757365645f32306d6d5f63616e6e6f6e98766973697465645f6d6f6e6f6c6974685f616d657269736899766973697465645f6d6f6e6f6c6974685f636572797368656e97766973697465645f6d6f6e6f6c6974685f637973736f7297766973697465645f6d6f6e6f6c6974685f6573616d697299766973697465645f6d6f6e6f6c6974685f666f72736572616c99766973697465645f6d6f6e6f6c6974685f697368756e64617298766973697465645f6d6f6e6f6c6974685f7365617268757397766973697465645f6d6f6e6f6c6974685f736f6c73617292757365645f6e635f6865765f66616c636f6e99757365645f6e635f6865765f7363617474657263616e6e6f6e93757365645f6e635f6865765f73706172726f7791757365645f61726d6f725f736970686f6e9f757365645f706572656772696e655f6475616c5f6d616368696e655f67756e9f757365645f706572656772696e655f6475616c5f726f636b65745f706f647399757365645f706572656772696e655f6d65636868616d6d65729e757365645f706572656772696e655f7061727469636c655f63616e6e6f6e96757365645f706572656772696e655f73706172726f7791757365645f3130356d6d5f63616e6e6f6e92757365645f31356d6d5f636861696e67756ea0757365645f70756c7365645f7061727469636c655f616363656c657261746f7293757365645f726f74617279636861696e67756e9f766973697465645f6465636f6e737472756374696f6e5f7465726d696e616c95757365645f736b7967756172645f776561706f6e7391766973697465645f67656e657261746f7291757365645f67617573735f63616e6e6f6e89757365645f7472656b95757365645f76616e67756172645f776561706f6e73a4766973697465645f616e6369656e745f6169725f76656869636c655f7465726d696e616ca2766973697465645f616e6369656e745f65717569706d656e745f7465726d696e616c96766973697465645f6f726465725f7465726d696e616ca7766973697465645f616e6369656e745f67726f756e645f76656869636c655f7465726d696e616c9f766973697465645f67726f756e645f76656869636c655f7465726d696e616c97757365645f76756c747572655f626f6d6261726469657298757365645f76756c747572655f6e6f73655f63616e6e6f6e98757365645f76756c747572655f7461696c5f63616e6e6f6e97757365645f776173705f776561706f6e5f73797374656d91766973697465645f636861726c6965303191766973697465645f636861726c6965303291766973697465645f636861726c6965303391766973697465645f636861726c6965303491766973697465645f636861726c6965303591766973697465645f636861726c6965303691766973697465645f636861726c6965303791766973697465645f636861726c6965303891766973697465645f636861726c6965303996766973697465645f67696e6765726d616e5f6174617298766973697465645f67696e6765726d616e5f646168616b6196766973697465645f67696e6765726d616e5f6876617296766973697465645f67696e6765726d616e5f697a686199766973697465645f67696e6765726d616e5f6a616d7368696498766973697465645f67696e6765726d616e5f6d697468726198766973697465645f67696e6765726d616e5f726173686e7599766973697465645f67696e6765726d616e5f7372616f73686198766973697465645f67696e6765726d616e5f79617a61746195766973697465645f67696e6765726d616e5f7a616c8e766973697465645f736c656430318e766973697465645f736c656430328e766973697465645f736c656430348e766973697465645f736c656430358e766973697465645f736c656430368e766973697465645f736c656430378e766973697465645f736c6564303897766973697465645f736e6f776d616e5f616d657269736898766973697465645f736e6f776d616e5f636572797368656e96766973697465645f736e6f776d616e5f637973736f7296766973697465645f736e6f776d616e5f6573616d697298766973697465645f736e6f776d616e5f666f72736572616c96766973697465645f736e6f776d616e5f686f7373696e98766973697465645f736e6f776d616e5f697368756e64617297766973697465645f736e6f776d616e5f7365617268757396766973697465645f736e6f776d616e5f736f6c736172857567643036857567643035857567643034857567643033857567643032857567643031856d61703939856d61703938856d61703937856d61703936856d61703135856d61703134856d61703131856d61703038856d61703034856d61703035856d61703033856d61703031856d61703036856d61703032856d61703039856d61703037856d617031300300000091747261696e696e675f73746172745f6e638b747261696e696e675f75698c747261696e696e675f6d61700000000000000000000000000000000000000000800000003d0c04d350840240000010000602429660f80c80000c8004200c1b81480000020000c046f18a47019000019000ca4644304900000040001809e6bb052032000008001a84787211200000080003010714889c06400000100320ff0a42e4000001009e95a7342e03200000080003010408c914064000000001198990c4e4000001000060223b9b2180c800000a00081c20c92c800003600414ec172d900000040001808de1284a0320000320008ef1c336b20000078011d830e6f6400000600569c417e2c80000020000c04102502f019000008c00ce31027d99000000400018099e6146203200004b0015a7d44002f720000008000301040c18dc064000023000b1240800636400000100006020e0e92280c80000c800081650c00cfc800006400ce32a1801a59000000400018099e6fc3e03200004b00058b14680463200000080003010742610c064000043000b16c8880916400000100006020e0d01580c80000c8006714e24012cc80000020000c04cf25c190190000258001032e240307900000c8019c74470061b2000000800030133ced8fc0640000960012d9a8d00f0640000010025b9c1401e4c8000002004b6b23c03d1900000040098f585007b3200000080131a58c00f864000001002536f1c01f4c8000002004a64e2a03f190000004015e1b4580873200000080003010711f8a406400000100110a00c010ee400000100006020e2a51380c8000002002218d21021ec80000020000c041c40249019000000400af18a44043f90000004000180838b44760320000008015e38c80088320000008000301071490cc064000001002bc35890110e400000100006020e2052180c800000200221f90d0222c80000020000c041c5e447019000000400442e62e044790000004000180838af032032000000800886d08c089320000008000301071738740640000010011098898112e400000100006020e2361c80c8000002002212a1b0226c80000020000c041c512170190000004004420a32044f900000040001808389104a0320000008008874c8808a3200000080003010715907c06400000100110c0898114e400000100006020e2771a80c800000200578bd13022ac80000020000c041c424330190000004004423848045790000004000180838bfc32032000000801a86506008b320000008000301071030dc06400000100129f68a0117640000010026353110232c8000002004b69438046d90000004015e2887008eb200000080003010715909406400000100350fb8e011de400000100006020e2881980c8000002005786d0f023cc80000020000c041c4cc3b019000000400af1ba1c047b90000004000180838af872032000000800886344408fb20000008000301071620d406400000100110c10b011fe400000100006020e2870d80c800000200578f30c0240c80000020000c041c5863b019000000400442ee300483900000040001808388605e032000000801a86f03c090b200000080003010712a8fc064000001002bc0d858121e400000100006020e2521c80c800000200578b7230244c80000020000c041c49629019000000400d434026048b90000004000180838afc42032000000801a86d864091b200000080003010711989c064000001003508c8c8123e400000100006020e2a82280c8000002006a14f110248c80000020000c041c4be21019000000400af12640049390000004000180838a54720320000008015e33430092b20000008000301071228cc064000001003546e8d432400000100004f34a631139000004001b0834723120000008000204000c2ed0fa1c800000200a8432234a90000004000180952b248a0320000018004024c569d20000008000250a4d0ebc480000020000c04a24bc43019000000c00e0" val string_ccrider = 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" @@ -92,6 +117,7 @@ class DetailedCharacterDataTest extends Specification { a.armor mustEqual 50 //standard exosuit value a.staminaMax mustEqual 100 a.stamina mustEqual 100 + a.max_field mustEqual None a.certs mustEqual List( CertificationType.StandardAssault, CertificationType.MediumAssault, @@ -279,6 +305,7 @@ class DetailedCharacterDataTest extends Specification { a.armor mustEqual 50 //standard exosuit value a.staminaMax mustEqual 100 a.stamina mustEqual 100 + a.max_field mustEqual None a.certs mustEqual List( CertificationType.StandardAssault, CertificationType.MediumAssault, @@ -398,6 +425,203 @@ class DetailedCharacterDataTest extends Specification { } } + "decode (max)" in { + PacketCoding.DecodePacket(string_max).require match { + case ObjectCreateDetailedMessage(_, _, _, _, data) => + //this test is mainly for an alternate bitstream parsing order + //the object produced is massive and most of it is already covered in other tests + //only certain details towards the end of the stream will be checked + data match { + case Some(DetailedPlayerData(Some(p), basic, char, inv, hand)) => + basic match { + case CharacterAppearanceData(a, b, ribbons) => + a.app.name mustEqual "HaHaATRMax" + a.app.faction mustEqual PlanetSideEmpire.TR + a.app.sex mustEqual CharacterGender.Male + a.app.head mustEqual 57 + a.app.voice mustEqual CharacterVoice.Voice1 + a.black_ops mustEqual false + a.jammered mustEqual false + a.exosuit mustEqual ExoSuitType.MAX + a.unk1 mustEqual true + a.unk2 mustEqual None + a.unk3 mustEqual None + a.unk4 mustEqual 0 + a.unk5 mustEqual 1 + a.unk6 mustEqual 41605870L + a.unk7 mustEqual 0 + a.unk8 mustEqual 0 + a.unk9 mustEqual 0 + a.unkA mustEqual 65535 + + b.outfit_name mustEqual "" + b.outfit_logo mustEqual 0 + b.backpack mustEqual false + b.facingPitch mustEqual 348.75f + b.facingYawUpper mustEqual 0 + b.lfs mustEqual true + b.grenade_state mustEqual GrenadeState.None + b.is_cloaking mustEqual false + b.charging_pose mustEqual false + b.on_zipline mustEqual None + b.unk0 mustEqual 0L + b.unk1 mustEqual false + b.unk2 mustEqual false + b.unk3 mustEqual false + b.unk4 mustEqual false + b.unk5 mustEqual false + b.unk6 mustEqual false + b.unk7 mustEqual false + + ribbons.upper mustEqual MeritCommendation.None + ribbons.middle mustEqual MeritCommendation.None + ribbons.lower mustEqual MeritCommendation.None + ribbons.tos mustEqual MeritCommendation.None + case _ => + ko + } + + DetailedCharacterData.isBR24(char.a.bep) mustEqual false //br5+ + char match { + case DetailedCharacterData(a, b) => + a.bep mustEqual 15301L + a.cep mustEqual 0L + a.healthMax mustEqual 120 + a.health mustEqual 120 + a.armor mustEqual 641 + a.staminaMax mustEqual 100 + a.stamina mustEqual 100 + a.max_field mustEqual Some(0) //important! + a.certs mustEqual List( + CertificationType.StandardAssault, + CertificationType.MediumAssault, + CertificationType.StandardExoSuit, + CertificationType.AgileExoSuit, + CertificationType.UniMAX + ) + a.unk1 mustEqual 0L + a.unk2 mustEqual 0L + a.unk3 mustEqual 0L + a.unk4 mustEqual false + a.unk5 mustEqual 32831L + a.unk6 mustEqual 0 + a.unk7 mustEqual 0 + a.unk8 mustEqual 0L + a.unk9 mustEqual List(0, 0, 0, 0, 0, 0) + + b.implants mustEqual Nil + b.firstTimeEvents mustEqual List( + "xpe_battle_rank_3", + "xpe_bind_facility", + "xpe_instant_action", + "xpe_battle_rank_4", + "xpe_battle_rank_2", + "xpe_sanctuary_help", + "xpe_drop_pod", + "xpe_orbital_shuttle", + "xpe_battle_rank_5", + "xpe_th_nonsanc", + "xpe_th_ground_p", + "xpe_th_ammo", + "xpe_th_firemodes", + "xpe_th_max", + "visited_spitfire_turret", + "visited_wall_turret", + "visited_resource_silo", + "visited_certification_terminal", + "visited_med_terminal", + "visited_broadcast_warpgate", + "used_phalanx", + "visited_air_vehicle_terminal", + "visited_bfr_terminal", + "used_cycler", + "visited_galaxy_terminal", + "visited_implant_terminal", + "visited_external_door_lock", + "visited_respawn_terminal", + "visited_locker", + "visited_motion_sensor", + "used_grenade_plasma", + "used_rek", + "used_repeater", + "visited_deconstruction_terminal", + "visited_secondary_capture", + "used_suppressor", + "used_trhev_burster", + "used_trhev_dualcycler", + "used_trhev_pounder", + "visited_capture_terminal", + "visited_order_terminal", + "visited_ground_vehicle_terminal", + "map12", + "map10", + "map09", + "map05", + "map03", + "map02" + ) + b.tutorials mustEqual Nil + b.cosmetics mustEqual None + b.unk1 mustEqual None + b.unk2 mustEqual Nil + b.unk3 mustEqual Nil + b.unk4 mustEqual 0L + b.unk5 mustEqual 0L + b.unk6 mustEqual 0L + b.unk7 mustEqual 0L + b.unk8 mustEqual 0L + b.unk9 mustEqual Some(DCDExtra2(0, 0)) + b.unkA mustEqual Nil + b.unkB mustEqual Nil + b.unkC mustEqual false + case _ => + ko + } + //inventory + inv.isDefined mustEqual true + inv.get.contents.size mustEqual 19 + val contents = inv.get.contents + //0 + contents.head mustEqual InternalSlot(889, PlanetSideGUID(2), 0, + DetailedWeaponData(0,8,0, List( + InternalSlot(265, PlanetSideGUID(3), 0, DetailedAmmoBoxData(8,200)), + InternalSlot(265, PlanetSideGUID(4), 1, DetailedAmmoBoxData(8,200)), + InternalSlot(265, PlanetSideGUID(5), 2, DetailedAmmoBoxData(8,200)) + )) + ) + contents(1) mustEqual InternalSlot(175, PlanetSideGUID(6), 4, + DetailedWeaponData(0,8,0, List( + InternalSlot(540, PlanetSideGUID(7), 0, DetailedAmmoBoxData(8,1)) + )) + ) + contents(2) mustEqual InternalSlot(456, PlanetSideGUID(8), 5, DetailedLockerContainerData(8, None)) + contents(3) mustEqual InternalSlot(265, PlanetSideGUID(9), 6, DetailedAmmoBoxData(8, 36)) + contents(4) mustEqual InternalSlot(265, PlanetSideGUID(10), 10, DetailedAmmoBoxData(8, 100)) + contents(5) mustEqual InternalSlot(265, PlanetSideGUID(11), 14, DetailedAmmoBoxData(8, 100)) + contents(6) mustEqual InternalSlot(265, PlanetSideGUID(12), 18, DetailedAmmoBoxData(8, 100)) + contents(7) mustEqual InternalSlot(265, PlanetSideGUID(13), 70, DetailedAmmoBoxData(8, 100)) + contents(8) mustEqual InternalSlot(265, PlanetSideGUID(14), 74, DetailedAmmoBoxData(8, 100)) + contents(9) mustEqual InternalSlot(265, PlanetSideGUID(15), 78, DetailedAmmoBoxData(8, 100)) + contents(10) mustEqual InternalSlot(265, PlanetSideGUID(16), 82, DetailedAmmoBoxData(8, 100)) + contents(11) mustEqual InternalSlot(536, PlanetSideGUID(17), 134, DetailedAmmoBoxData(8, 1)) + contents(12) mustEqual InternalSlot(536, PlanetSideGUID(18), 138, DetailedAmmoBoxData(8, 1)) + contents(13) mustEqual InternalSlot(536, PlanetSideGUID(19), 142, DetailedAmmoBoxData(8, 1)) + contents(14) mustEqual InternalSlot(536, PlanetSideGUID(20), 146, DetailedAmmoBoxData(8, 1)) + contents(15) mustEqual InternalSlot(536, PlanetSideGUID(21), 166, DetailedAmmoBoxData(8, 1)) + contents(16) mustEqual InternalSlot(536, PlanetSideGUID(22), 170, DetailedAmmoBoxData(8, 1)) + contents(17) mustEqual InternalSlot(536, PlanetSideGUID(23), 174, DetailedAmmoBoxData(8, 1)) + contents(18) mustEqual InternalSlot(536, PlanetSideGUID(24), 178, DetailedAmmoBoxData(8, 1)) + + + hand mustEqual DrawnSlot.Pistol1 + case _ => + ko + } + case _ => + ko + } + } + "decode (BR32)" in { PacketCoding.DecodePacket(string_br32).require match { case ObjectCreateDetailedMessage(_, _, _, _, data) => @@ -464,6 +688,7 @@ class DetailedCharacterDataTest extends Specification { a.armor mustEqual 100 //standard exosuit value a.staminaMax mustEqual 100 a.stamina mustEqual 46 + a.max_field mustEqual None a.certs mustEqual List( CertificationType.StandardAssault, CertificationType.MediumAssault, @@ -926,6 +1151,7 @@ class DetailedCharacterDataTest extends Specification { a.unk5 mustEqual 32831L a.staminaMax mustEqual 100 a.stamina mustEqual 100 + a.max_field mustEqual None a.unk6 mustEqual 0 a.unk7 mustEqual 6 a.unk8 mustEqual 3165669L @@ -1064,6 +1290,7 @@ class DetailedCharacterDataTest extends Specification { 50, 32831L, 100, 100, + None, 0, 0, 0L, List(0, 0, 0, 0, 0, 0), List( @@ -1184,6 +1411,7 @@ class DetailedCharacterDataTest extends Specification { 50, 32831L, 100, 100, + None, 0, 0, 0L, List(0, 0, 0, 0, 0, 0), List( @@ -1240,6 +1468,182 @@ class DetailedCharacterDataTest extends Specification { //TODO work on DetailedCharacterData to make this pass as a single stream } + "encode (max)" in { + val pos : PlacementData = PlacementData( + Vector3(3990.7734f, 3656.5781f, 230.70312f), + Vector3(0, 0, 67.5f), + None + ) + val aa : Int=>CharacterAppearanceA = CharacterAppearanceA( + BasicCharacterData( + "HaHaATRMax", + PlanetSideEmpire.TR, + CharacterGender.Male, + 57, + CharacterVoice.Voice1 + ), + false, + false, + true, + None, + false, + ExoSuitType.MAX, + None, + 0, + 1, + 41605870L, + 0, + 0, + 0, + 65535 + ) + val ab : (Boolean,Int)=>CharacterAppearanceB = CharacterAppearanceB( + 0L, + "", + 0, + false, + false, + false, + false, + false, + 348.75f, 0, + true, + GrenadeState.None, + false, + false, + false, + false, + false, + None + ) + + val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData( + aa, ab, + RibbonBars() + ) + val ba : DetailedCharacterA = DetailedCharacterA( + 15301L, + 0L, + 0L, 0L, 0L, + 120, 120, + false, + 641, + 32831L, + 100, 100, + Some(0), + 0, 0, 0L, + List(0, 0, 0, 0, 0, 0), + List( + CertificationType.StandardAssault, + CertificationType.MediumAssault, + CertificationType.StandardExoSuit, + CertificationType.AgileExoSuit, + CertificationType.UniMAX + ) + ) + val bb : (Long, Option[Int])=>DetailedCharacterB = DetailedCharacterB( + None, + Nil, + Nil, Nil, + List( + "xpe_battle_rank_3", + "xpe_bind_facility", + "xpe_instant_action", + "xpe_battle_rank_4", + "xpe_battle_rank_2", + "xpe_sanctuary_help", + "xpe_drop_pod", + "xpe_orbital_shuttle", + "xpe_battle_rank_5", + "xpe_th_nonsanc", + "xpe_th_ground_p", + "xpe_th_ammo", + "xpe_th_firemodes", + "xpe_th_max", + "visited_spitfire_turret", + "visited_wall_turret", + "visited_resource_silo", + "visited_certification_terminal", + "visited_med_terminal", + "visited_broadcast_warpgate", + "used_phalanx", + "visited_air_vehicle_terminal", + "visited_bfr_terminal", + "used_cycler", + "visited_galaxy_terminal", + "visited_implant_terminal", + "visited_external_door_lock", + "visited_respawn_terminal", + "visited_locker", + "visited_motion_sensor", + "used_grenade_plasma", + "used_rek", + "used_repeater", + "visited_deconstruction_terminal", + "visited_secondary_capture", + "used_suppressor", + "used_trhev_burster", + "used_trhev_dualcycler", + "used_trhev_pounder", + "visited_capture_terminal", + "visited_order_terminal", + "visited_ground_vehicle_terminal", + "map12", + "map10", + "map09", + "map05", + "map03", + "map02" + ), + Nil, + 0L, 0L, 0L, 0L, 0L, + Some(DCDExtra2(0, 0)), + Nil, Nil, false, + None + ) + val char : (Option[Int])=>DetailedCharacterData = + (pad_length : Option[Int]) => DetailedCharacterData(ba, bb(ba.bep, pad_length))(pad_length) + + val inv = InventoryData( + List( + InternalSlot(889, PlanetSideGUID(2), 0, + DetailedWeaponData(0,8,0, List( + InternalSlot(265, PlanetSideGUID(3), 0, DetailedAmmoBoxData(8,200)), + InternalSlot(265, PlanetSideGUID(4), 1, DetailedAmmoBoxData(8,200)), + InternalSlot(265, PlanetSideGUID(5), 2, DetailedAmmoBoxData(8,200)) + )) + ), + InternalSlot(175, PlanetSideGUID(6), 4, + DetailedWeaponData(0,8,0, List( + InternalSlot(540, PlanetSideGUID(7), 0, DetailedAmmoBoxData(8,1)) + )) + ), + InternalSlot(456, PlanetSideGUID(8), 5, DetailedLockerContainerData(8, None)), + InternalSlot(265, PlanetSideGUID(9), 6, DetailedAmmoBoxData(8, 36)), + InternalSlot(265, PlanetSideGUID(10), 10, DetailedAmmoBoxData(8, 100)), + InternalSlot(265, PlanetSideGUID(11), 14, DetailedAmmoBoxData(8, 100)), + InternalSlot(265, PlanetSideGUID(12), 18, DetailedAmmoBoxData(8, 100)), + InternalSlot(265, PlanetSideGUID(13), 70, DetailedAmmoBoxData(8, 100)), + InternalSlot(265, PlanetSideGUID(14), 74, DetailedAmmoBoxData(8, 100)), + InternalSlot(265, PlanetSideGUID(15), 78, DetailedAmmoBoxData(8, 100)), + InternalSlot(265, PlanetSideGUID(16), 82, DetailedAmmoBoxData(8, 100)), + InternalSlot(536, PlanetSideGUID(17), 134, DetailedAmmoBoxData(8, 1)), + InternalSlot(536, PlanetSideGUID(18), 138, DetailedAmmoBoxData(8, 1)), + InternalSlot(536, PlanetSideGUID(19), 142, DetailedAmmoBoxData(8, 1)), + InternalSlot(536, PlanetSideGUID(20), 146, DetailedAmmoBoxData(8, 1)), + InternalSlot(536, PlanetSideGUID(21), 166, DetailedAmmoBoxData(8, 1)), + InternalSlot(536, PlanetSideGUID(22), 170, DetailedAmmoBoxData(8, 1)), + InternalSlot(536, PlanetSideGUID(23), 174, DetailedAmmoBoxData(8, 1)), + InternalSlot(536, PlanetSideGUID(24), 178, DetailedAmmoBoxData(8, 1)) + ) + ) + val obj = DetailedPlayerData(pos, app, char, inv, DrawnSlot.Pistol1) + + val msg = ObjectCreateDetailedMessage(ObjectClass.avatar, PlanetSideGUID(1), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string_max + } + "encode (character, br32)" in { val pos : PlacementData = PlacementData( Vector3(5500.0f, 3800.0f, 71.484375f), @@ -1307,6 +1711,7 @@ class DetailedCharacterDataTest extends Specification { 100, 32831L, 100, 46, + None, 0, 4, 3278759L, List(0, 0, 0, 0, 0, 0), List( @@ -1906,6 +2311,7 @@ class DetailedCharacterDataTest extends Specification { 50, 32831, 100, 100, + None, 0, 6, 3165669, diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 815410238..6387105cb 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -1460,17 +1460,17 @@ class WorldSessionActor extends Actor with MDCContextAware { } else { //remove potential MAX weapon + tplayer.DrawnSlot = Player.HandsDownSlot + sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true)) val normalWeapons = if(originalSuit == ExoSuitType.MAX) { val (maxWeapons, normalWeapons) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max) maxWeapons.foreach(entry => { taskResolver ! GUIDTask.UnregisterEquipment(entry.obj)(continent.GUID) }) + avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot)) normalWeapons } else { - tplayer.DrawnSlot = Player.HandsDownSlot - sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectHeld(tplayer.GUID, Player.HandsDownSlot)) beforeHolsters } //fill holsters @@ -2879,7 +2879,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //we're driving the vehicle player.Position = pos //convenient if(seat.ControlledWeapon.isEmpty) { - player.Orientation = Vector3(0f, 0f, ang.z) //convenient + player.Orientation = Vector3.z(ang.z) //convenient } obj.Position = pos obj.Orientation = ang diff --git a/pslogin/src/test/scala/PacketCodingActorTest.scala b/pslogin/src/test/scala/PacketCodingActorTest.scala index dc446d0dd..1628fe5b6 100644 --- a/pslogin/src/test/scala/PacketCodingActorTest.scala +++ b/pslogin/src/test/scala/PacketCodingActorTest.scala @@ -476,6 +476,7 @@ class PacketCodingActorITest extends ActorTest { 100, 100, 50, 100, 100, + None, List(CertificationType.StandardAssault, CertificationType.MediumAssault, CertificationType.ATV, CertificationType.Harasser, CertificationType.StandardExoSuit, CertificationType.AgileExoSuit, CertificationType.ReinforcedExoSuit), List(), List(), @@ -601,6 +602,7 @@ class PacketCodingActorKTest extends ActorTest { 50, 32831L, 100, 100, + None, 0, 0, 0L, List(0, 0, 0, 0, 0, 0), List(