mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-03-16 02:40:43 +00:00
Refactored CharacterData and DetailedCharacterData to be a component of PlayerData and DetailedPlayerData, respectively. Position information is now optional; inventory data and exposed hand data are also removed into PlayerData and DetailedPlayerData. String padding management has been preserved. Tests and packet converters have been repaired.
This commit is contained in:
parent
a9db4b5820
commit
052a318285
13 changed files with 1134 additions and 940 deletions
|
|
@ -3,47 +3,52 @@ package net.psforever.objects.definition.converter
|
|||
|
||||
import net.psforever.objects.{EquipmentSlot, Player}
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.packet.game.objectcreate.{BasicCharacterData, CharacterAppearanceData, CharacterData, Cosmetics, DetailedCharacterData, DrawnSlot, ImplantEffects, ImplantEntry, InternalSlot, InventoryData, PlacementData, RibbonBars, UniformStyle}
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
import net.psforever.types.{GrenadeState, ImplantType}
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.util.{Success, Try}
|
||||
|
||||
class AvatarConverter extends ObjectCreateConverter[Player]() {
|
||||
override def ConstructorData(obj : Player) : Try[CharacterData] = {
|
||||
override def ConstructorData(obj : Player) : Try[PlayerData] = {
|
||||
val MaxArmor = obj.MaxArmor
|
||||
Success(
|
||||
CharacterData(
|
||||
Success(
|
||||
PlayerData.apply(
|
||||
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
|
||||
MakeAppearanceData(obj),
|
||||
255 * obj.Health / obj.MaxHealth, //TODO not precise
|
||||
if(MaxArmor == 0) { 0 } else { 255 * obj.Armor / MaxArmor }, //TODO not precise
|
||||
DressBattleRank(obj),
|
||||
DressCommandRank(obj),
|
||||
recursiveMakeImplantEffects(obj.Implants.iterator),
|
||||
MakeCosmetics(obj.BEP),
|
||||
CharacterData(
|
||||
255 * obj.Health / obj.MaxHealth, //TODO not precise
|
||||
if(MaxArmor == 0) { 0 } else { 255 * obj.Armor / MaxArmor }, //TODO not precise
|
||||
DressBattleRank(obj),
|
||||
DressCommandRank(obj),
|
||||
recursiveMakeImplantEffects(obj.Implants.iterator),
|
||||
MakeCosmetics(obj.BEP)
|
||||
),
|
||||
InventoryData(MakeHolsters(obj, BuildEquipment).sortBy(_.parentSlot)), //TODO is sorting necessary?
|
||||
GetDrawnSlot(obj)
|
||||
)
|
||||
)
|
||||
//TODO tidy this mess up
|
||||
}
|
||||
|
||||
override def DetailedConstructorData(obj : Player) : Try[DetailedCharacterData] = {
|
||||
override def DetailedConstructorData(obj : Player) : Try[DetailedPlayerData] = {
|
||||
Success(
|
||||
DetailedCharacterData(
|
||||
DetailedPlayerData.apply(
|
||||
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
|
||||
MakeAppearanceData(obj),
|
||||
obj.BEP,
|
||||
obj.CEP,
|
||||
obj.MaxHealth,
|
||||
obj.Health,
|
||||
obj.Armor,
|
||||
obj.MaxStamina,
|
||||
obj.Stamina,
|
||||
obj.Certifications.toList.sortBy(_.id), //TODO is sorting necessary?
|
||||
MakeImplantEntries(obj),
|
||||
List.empty[String], //TODO fte list
|
||||
List.empty[String], //TODO tutorial list
|
||||
MakeCosmetics(obj.BEP),
|
||||
DetailedCharacterData(
|
||||
obj.BEP,
|
||||
obj.CEP,
|
||||
obj.MaxHealth,
|
||||
obj.Health,
|
||||
obj.Armor,
|
||||
obj.MaxStamina,
|
||||
obj.Stamina,
|
||||
obj.Certifications.toList.sortBy(_.id), //TODO is sorting necessary?
|
||||
MakeImplantEntries(obj),
|
||||
List.empty[String], //TODO fte list
|
||||
List.empty[String], //TODO tutorial list
|
||||
MakeCosmetics(obj.BEP)
|
||||
),
|
||||
InventoryData((MakeHolsters(obj, BuildDetailedEquipment) ++ MakeFifthSlot(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)),
|
||||
GetDrawnSlot(obj)
|
||||
)
|
||||
|
|
@ -55,9 +60,8 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
|
|||
* @param obj the `Player` game object
|
||||
* @return the resulting `CharacterAppearanceData`
|
||||
*/
|
||||
private def MakeAppearanceData(obj : Player) : CharacterAppearanceData = {
|
||||
private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
||||
CharacterAppearanceData(
|
||||
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
|
||||
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, obj.Voice),
|
||||
0,
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,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.{BasicCharacterData, CharacterAppearanceData, CharacterData, DetailedCharacterData, ImplantEntry, InternalSlot, InventoryData, PlacementData, RibbonBars}
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
import net.psforever.types.{GrenadeState, ImplantType}
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
|
@ -15,19 +15,22 @@ import scala.util.{Failure, Success, Try}
|
|||
* Details that would not be apparent on that screen such as implants or certifications are ignored.
|
||||
*/
|
||||
class CharacterSelectConverter extends AvatarConverter {
|
||||
override def ConstructorData(obj : Player) : Try[CharacterData] = Failure(new Exception("CharacterSelectConverter should not be used to generate CharacterData"))
|
||||
override def ConstructorData(obj : Player) : Try[PlayerData] = Failure(new Exception("CharacterSelectConverter should not be used to generate CharacterData"))
|
||||
|
||||
override def DetailedConstructorData(obj : Player) : Try[DetailedCharacterData] = {
|
||||
override def DetailedConstructorData(obj : Player) : Try[DetailedPlayerData] = {
|
||||
Success(
|
||||
DetailedCharacterData(
|
||||
DetailedPlayerData.apply(
|
||||
PlacementData(0, 0, 0),
|
||||
MakeAppearanceData(obj),
|
||||
obj.BEP,
|
||||
obj.CEP,
|
||||
1, 1, 0, 1, 1,
|
||||
Nil,
|
||||
MakeImplantEntries(obj), //necessary for correct stream length
|
||||
Nil, Nil,
|
||||
MakeCosmetics(obj.BEP),
|
||||
DetailedCharacterData(
|
||||
obj.BEP,
|
||||
obj.CEP,
|
||||
1, 1, 0, 1, 1,
|
||||
Nil,
|
||||
MakeImplantEntries(obj), //necessary for correct stream length
|
||||
Nil, Nil,
|
||||
MakeCosmetics(obj.BEP)
|
||||
),
|
||||
InventoryData(recursiveMakeHolsters(obj.Holsters().iterator)),
|
||||
GetDrawnSlot(obj)
|
||||
)
|
||||
|
|
@ -40,9 +43,8 @@ class CharacterSelectConverter extends AvatarConverter {
|
|||
* @see `AvatarConverter.MakeAppearanceData`
|
||||
* @return the resulting `CharacterAppearanceData`
|
||||
*/
|
||||
private def MakeAppearanceData(obj : Player) : CharacterAppearanceData = {
|
||||
private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
||||
CharacterAppearanceData(
|
||||
PlacementData(0f, 0f, 0f),
|
||||
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, 1),
|
||||
0,
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -3,23 +3,26 @@ package net.psforever.objects.definition.converter
|
|||
|
||||
import net.psforever.objects.{EquipmentSlot, Player}
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.packet.game.objectcreate.{BasicCharacterData, CharacterAppearanceData, CharacterData, DetailedCharacterData, DrawnSlot, InternalSlot, InventoryData, PlacementData, RibbonBars}
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
import net.psforever.types.{CharacterGender, GrenadeState, Vector3}
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
class CorpseConverter extends AvatarConverter {
|
||||
override def ConstructorData(obj : Player) : Try[CharacterData] =
|
||||
override def ConstructorData(obj : Player) : Try[PlayerData] =
|
||||
Failure(new Exception("CorpseConverter should not be used to generate CharacterData"))
|
||||
|
||||
override def DetailedConstructorData(obj : Player) : Try[DetailedCharacterData] = {
|
||||
override def DetailedConstructorData(obj : Player) : Try[DetailedPlayerData] = {
|
||||
Success(
|
||||
DetailedCharacterData(
|
||||
DetailedPlayerData.apply(
|
||||
PlacementData(obj.Position, Vector3(0,0, obj.Orientation.z)),
|
||||
MakeAppearanceData(obj),
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
Nil, Nil, Nil, Nil,
|
||||
None,
|
||||
DetailedCharacterData(
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
Nil, Nil, Nil, Nil,
|
||||
None
|
||||
),
|
||||
InventoryData((MakeHolsters(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)),
|
||||
DrawnSlot.None
|
||||
)
|
||||
|
|
@ -31,9 +34,8 @@ class CorpseConverter extends AvatarConverter {
|
|||
* @param obj the `Player` game object
|
||||
* @return the resulting `CharacterAppearanceData`
|
||||
*/
|
||||
private def MakeAppearanceData(obj : Player) : CharacterAppearanceData = {
|
||||
private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
||||
CharacterAppearanceData(
|
||||
PlacementData(obj.Position, Vector3(0,0, obj.Orientation.z)),
|
||||
BasicCharacterData(obj.Name, obj.Faction, CharacterGender.Male, 0, 0),
|
||||
0,
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import shapeless.{::, HNil}
|
|||
* `5 - male_5 female_5`<br>
|
||||
* `6 - female_1 no voice`<br>
|
||||
* `7 - female_2 no voice`
|
||||
* @see `PlanetSideEmpire`<br>
|
||||
* `CharacaterGender`
|
||||
* @param name the unique name of the avatar;
|
||||
* minimum of two characters
|
||||
* @param faction the empire to which the avatar belongs
|
||||
|
|
@ -30,8 +32,6 @@ import shapeless.{::, HNil}
|
|||
* @param head the avatar's face and hair;
|
||||
* by row and column on the character creation screen, the high nibble is the row and the low nibble is the column
|
||||
* @param voice the avatar's voice selection
|
||||
* @see `PlanetSideEmpire`
|
||||
* @see `CharacaterGender`
|
||||
*/
|
||||
final case class BasicCharacterData(name : String,
|
||||
faction : PlanetSideEmpire.Value,
|
||||
|
|
@ -60,8 +60,12 @@ final case class BasicCharacterData(name : String,
|
|||
* <br>
|
||||
* Exploration:<br>
|
||||
* How do I crouch?
|
||||
* @param pos the position of the character in the world environment (in three coordinates)
|
||||
* @param basic_appearance the player's cardinal appearance settings
|
||||
* @see `CharacterData`<br>
|
||||
* `DetailedCharacterData`<br>
|
||||
* `ExoSuitType`<br>
|
||||
* `GrenadeState`<br>
|
||||
* `RibbonBars`
|
||||
* @param app the player's cardinal appearance settings
|
||||
* @param voice2 na;
|
||||
* affects the frequency by which the character's voice is heard (somehow);
|
||||
* commonly 3 for best results
|
||||
|
|
@ -86,16 +90,8 @@ final case class BasicCharacterData(name : String,
|
|||
* @param charging_pose animation pose for both charging modules and BFR imprinting
|
||||
* @param on_zipline player's model is changed into a faction-color ball of energy, as if on a zip line
|
||||
* @param ribbons the four merit commendation ribbon medals
|
||||
* @see `CharacterData`
|
||||
* @see `DetailedCharacterData`
|
||||
* @see `PlacementData`
|
||||
* @see `ExoSuitType`
|
||||
* @see `GrenadeState`
|
||||
* @see `RibbonBars`
|
||||
* @see `http://wiki.planetsidesyndicate.com/index.php?title=Outfit_Logo` for a list of outfit decals
|
||||
*/
|
||||
final case class CharacterAppearanceData(pos : PlacementData,
|
||||
basic_appearance : BasicCharacterData,
|
||||
final case class CharacterAppearanceData(app : BasicCharacterData,
|
||||
voice2 : Int,
|
||||
black_ops : Boolean,
|
||||
jammered : Boolean,
|
||||
|
|
@ -110,22 +106,29 @@ final case class CharacterAppearanceData(pos : PlacementData,
|
|||
is_cloaking : Boolean,
|
||||
charging_pose : Boolean,
|
||||
on_zipline : Boolean,
|
||||
ribbons : RibbonBars) extends StreamBitSize {
|
||||
ribbons : RibbonBars)
|
||||
(name_padding : Int) extends StreamBitSize {
|
||||
|
||||
override def bitsize : Long = {
|
||||
//factor guard bool values into the base size, not its corresponding optional field
|
||||
val placementSize : Long = pos.bitsize
|
||||
val nameStringSize : Long = StreamBitSize.stringBitSize(basic_appearance.name, 16) + CharacterAppearanceData.namePadding(pos.vel)
|
||||
val nameStringSize : Long = StreamBitSize.stringBitSize(app.name, 16) + CharacterAppearanceData.namePaddingRule(name_padding)
|
||||
val outfitStringSize : Long = StreamBitSize.stringBitSize(outfit_name, 16) + CharacterAppearanceData.outfitNamePadding
|
||||
val altModelSize = CharacterAppearanceData.altModelBit(this).getOrElse(0)
|
||||
335L + placementSize + nameStringSize + outfitStringSize + altModelSize
|
||||
335L + nameStringSize + outfitStringSize + altModelSize
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When a player is released-dead or attached to a zipline, their basic infantry model is replaced with a different one.
|
||||
* @return the length of the variable field that exists when using alternate models
|
||||
*/
|
||||
def altModelBit : Option[Int] = CharacterAppearanceData.altModelBit(this)
|
||||
}
|
||||
|
||||
object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
|
||||
/**
|
||||
* When a player is released-dead or attached to a zipline, their basic infantry model is replaced with a different one.
|
||||
* In the former casde, a backpack.
|
||||
* In the former case, a backpack.
|
||||
* In the latter case, a ball of colored energy.
|
||||
* In this state, the length of the stream of data is modified.
|
||||
* @param app the appearance
|
||||
|
|
@ -143,14 +146,13 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
|
|||
* The padding will always be a number 0-7.
|
||||
* @return the pad length in bits
|
||||
*/
|
||||
def namePadding(move : Option[_]) : Int = {
|
||||
if(move.isDefined) {
|
||||
2
|
||||
def namePaddingRule(pad : Int) : Int =
|
||||
if(pad == 0) {
|
||||
1 //normal alignment padding for the string
|
||||
}
|
||||
else {
|
||||
4
|
||||
pad //custom padding value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the padding of the outfit's name.
|
||||
|
|
@ -161,77 +163,78 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
|
|||
6
|
||||
}
|
||||
|
||||
implicit val codec : Codec[CharacterAppearanceData] = (
|
||||
("pos" | PlacementData.codec) >>:~ { pos =>
|
||||
("faction" | PlanetSideEmpire.codec) ::
|
||||
("black_ops" | bool) ::
|
||||
(("alt_model" | bool) >>:~ { alt_model => //modifies stream format (to display alternate player models)
|
||||
def codec(name_padding : Int) : Codec[CharacterAppearanceData] = (
|
||||
("faction" | PlanetSideEmpire.codec) ::
|
||||
("black_ops" | bool) ::
|
||||
(("alt_model" | bool) >>:~ { alt_model => //modifies stream format (to display alternate player models)
|
||||
ignore(1) :: //unknown
|
||||
("jammered" | bool) ::
|
||||
bool :: //crashes client
|
||||
uint(16) :: //unknown, but usually 0
|
||||
("name" | PacketHelpers.encodedWideStringAligned( namePaddingRule(name_padding) )) ::
|
||||
("exosuit" | ExoSuitType.codec) ::
|
||||
ignore(2) :: //unknown
|
||||
("sex" | CharacterGender.codec) ::
|
||||
("head" | uint8L) ::
|
||||
("voice" | uint(3)) ::
|
||||
("voice2" | uint2L) ::
|
||||
ignore(78) :: //unknown
|
||||
uint16L :: //usually either 0 or 65535
|
||||
uint32L :: //for outfit_name (below) to be visible in-game, this value should be non-zero
|
||||
("outfit_name" | PacketHelpers.encodedWideStringAligned( outfitNamePadding )) ::
|
||||
("outfit_logo" | uint8L) ::
|
||||
ignore(1) :: //unknown
|
||||
("jammered" | bool) ::
|
||||
bool :: //crashes client
|
||||
uint(16) :: //unknown, but usually 0
|
||||
("name" | PacketHelpers.encodedWideStringAligned( namePadding(pos.vel) )) ::
|
||||
("exosuit" | ExoSuitType.codec) ::
|
||||
ignore(2) :: //unknown
|
||||
("sex" | CharacterGender.codec) ::
|
||||
("head" | uint8L) ::
|
||||
("voice" | uint(3)) ::
|
||||
("voice2" | uint2L) ::
|
||||
ignore(78) :: //unknown
|
||||
uint16L :: //usually either 0 or 65535
|
||||
uint32L :: //for outfit_name (below) to be visible in-game, this value should be non-zero
|
||||
("outfit_name" | PacketHelpers.encodedWideStringAligned( outfitNamePadding )) ::
|
||||
("outfit_logo" | uint8L) ::
|
||||
ignore(1) :: //unknown
|
||||
("backpack" | bool) :: //requires alt_model flag (does NOT require health == 0)
|
||||
bool :: //stream misalignment when set
|
||||
("facingPitch" | Angular.codec_pitch) ::
|
||||
("facingYawUpper" | Angular.codec_yaw(0f)) ::
|
||||
ignore(1) :: //unknown
|
||||
conditional(alt_model, bool) :: //alt_model flag adds a bit before lfs
|
||||
ignore(1) :: //an alternate lfs?
|
||||
("lfs" | bool) ::
|
||||
("grenade_state" | GrenadeState.codec_2u) :: //note: bin10 and bin11 are neutral (bin00 is not defined)
|
||||
("is_cloaking" | bool) ::
|
||||
ignore(1) :: //unknown
|
||||
bool :: //stream misalignment when set
|
||||
("charging_pose" | bool) ::
|
||||
ignore(1) :: //alternate charging pose?
|
||||
("on_zipline" | bool) :: //requires alt_model flag
|
||||
("ribbons" | RibbonBars.codec)
|
||||
})
|
||||
}).exmap[CharacterAppearanceData] (
|
||||
("backpack" | bool) :: //requires alt_model flag (does NOT require health == 0)
|
||||
bool :: //stream misalignment when set
|
||||
("facingPitch" | Angular.codec_pitch) ::
|
||||
("facingYawUpper" | Angular.codec_yaw(0f)) ::
|
||||
ignore(1) :: //unknown
|
||||
conditional(alt_model, bool) :: //alt_model flag adds a bit before lfs
|
||||
ignore(1) :: //an alternate lfs?
|
||||
("lfs" | bool) ::
|
||||
("grenade_state" | GrenadeState.codec_2u) :: //note: bin10 and bin11 are neutral (bin00 is not defined)
|
||||
("is_cloaking" | bool) ::
|
||||
ignore(1) :: //unknown
|
||||
bool :: //stream misalignment when set
|
||||
("charging_pose" | bool) ::
|
||||
ignore(1) :: //alternate charging pose?
|
||||
("on_zipline" | bool) :: //requires alt_model flag
|
||||
("ribbons" | RibbonBars.codec)
|
||||
})
|
||||
).exmap[CharacterAppearanceData] (
|
||||
{
|
||||
case _ :: _ :: _ :: false :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: true :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: HNil |
|
||||
_ :: _ :: _ :: false :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: true :: _ :: HNil =>
|
||||
case _ :: _ :: false :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: true :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: HNil |
|
||||
_ :: _ :: false :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: true :: _ :: HNil =>
|
||||
Attempt.Failure(Err("invalid character appearance data; can not encode alternate model without required bit set"))
|
||||
|
||||
case pos :: faction :: bops :: _ :: _ :: jamd :: false :: 0 :: name :: suit :: _ :: sex :: head :: v1 :: v2 :: _ :: _ :: _/*has_outfit_name*/ :: outfit :: logo :: _ :: bpack :: false :: facingPitch :: facingYawUpper :: _ :: _ :: _ :: lfs :: gstate :: cloaking :: _ :: false :: charging :: _ :: zipline :: ribbons :: HNil =>
|
||||
case faction :: bops :: _ :: _ :: jamd :: false :: 0 :: name :: suit :: _ :: sex :: head :: v1 :: v2 :: _ :: _ :: _/*has_outfit_name*/ :: outfit :: logo :: _ :: bpack :: false :: facingPitch :: facingYawUpper :: _ :: _ :: _ :: lfs :: gstate :: cloaking :: _ :: false :: charging :: _ :: zipline :: ribbons :: HNil =>
|
||||
Attempt.successful(
|
||||
CharacterAppearanceData(pos, BasicCharacterData(name, faction, sex, head, v1), v2, bops, jamd, suit, outfit, logo, bpack, facingPitch, facingYawUpper, lfs, gstate, cloaking, charging, zipline, ribbons)
|
||||
CharacterAppearanceData(BasicCharacterData(name, faction, sex, head, v1), v2, bops, jamd, suit, outfit, logo, bpack, facingPitch, facingYawUpper, lfs, gstate, cloaking, charging, zipline, ribbons)(name_padding)
|
||||
)
|
||||
|
||||
case _ =>
|
||||
Attempt.Failure(Err("invalid character appearance data; can not encode"))
|
||||
},
|
||||
{
|
||||
case CharacterAppearanceData(_, BasicCharacterData(name, PlanetSideEmpire.NEUTRAL, _, _, _), _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
|
||||
case CharacterAppearanceData(BasicCharacterData(name, PlanetSideEmpire.NEUTRAL, _, _, _), _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
|
||||
Attempt.failure(Err(s"character $name's faction can not declare as neutral"))
|
||||
|
||||
case CharacterAppearanceData(pos, BasicCharacterData(name, faction, sex, head, v1), v2, bops, jamd, suit, outfit, logo, bpack, facingPitch, facingYawUpper, lfs, gstate, cloaking, charging, zipline, ribbons) =>
|
||||
case CharacterAppearanceData(BasicCharacterData(name, faction, sex, head, v1), v2, bops, jamd, suit, outfit, logo, bpack, facingPitch, facingYawUpper, lfs, gstate, cloaking, charging, zipline, ribbons) =>
|
||||
val has_outfit_name : Long = outfit.length.toLong //TODO this is a kludge
|
||||
var alt_model : Boolean = false
|
||||
var alt_model : Boolean = false
|
||||
var alt_model_extrabit : Option[Boolean] = None
|
||||
if(zipline || bpack) {
|
||||
alt_model = true
|
||||
alt_model_extrabit = Some(false)
|
||||
}
|
||||
Attempt.successful(
|
||||
pos :: faction :: bops :: alt_model :: () :: jamd :: false :: 0 :: name :: suit :: () :: sex :: head :: v1 :: v2 :: () :: 0 :: has_outfit_name :: outfit :: logo :: () :: bpack :: false :: facingPitch :: facingYawUpper :: () :: alt_model_extrabit :: () :: lfs :: gstate :: cloaking :: () :: false :: charging :: () :: zipline :: ribbons :: HNil
|
||||
faction :: bops :: alt_model :: () :: jamd :: false :: 0 :: name :: suit :: () :: sex :: head :: v1 :: v2 :: () :: 0 :: has_outfit_name :: outfit :: logo :: () :: bpack :: false :: facingPitch :: facingYawUpper :: () :: alt_model_extrabit :: () :: lfs :: gstate :: cloaking :: () :: false :: charging :: () :: zipline :: ribbons :: HNil
|
||||
)
|
||||
|
||||
case _ =>
|
||||
Attempt.Failure(Err("invalid character appearance data; can not decode"))
|
||||
}
|
||||
)
|
||||
|
||||
implicit val codec : Codec[CharacterAppearanceData] = codec(0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,27 +42,17 @@ object UniformStyle extends Enumeration {
|
|||
}
|
||||
|
||||
/**
|
||||
* A part of a representation of the avatar portion of `ObjectCreateMessage` packet data.
|
||||
* This densely-packed information outlines most of the specifics of depicting some other character.<br>
|
||||
* A representation of a portion of an avatar's `ObjectCreateDetailedMessage` packet data.<br>
|
||||
* <br>
|
||||
* The character created by this data is treated like an NPC from the perspective of the server.
|
||||
* This densely-packed information outlines most of the specifics required to depict some other player's character.
|
||||
* Someone else decides how that character is behaving and the server tells each client how to depict that behavior.
|
||||
* For that reason, the character is mostly for presentation purposes, rather than really being fleshed-out.
|
||||
* (As far as the client is concerned, nothing stops this character from being declared an "avatar."
|
||||
* A player would find such a client-controlled character lacking many important details and have poor equipment.
|
||||
* They would also be competing with some other player for input control, if they could control the character at all.)<br>
|
||||
* Of the inventory for this character, only the initial five weapon slots are defined.<br>
|
||||
* <br>
|
||||
* Divisions exist to make the data more manageable.
|
||||
* The first division of data only manages the general appearance of the player's in-game model.
|
||||
* The second division (currently, the fields actually in this class) manages the status of the character.
|
||||
* In general, it passes more simplified data about the character, the minimum that is necessary to explain status to some other player.
|
||||
* For example, health and armor are percentages, and are depicted as bars over the player's head near the nameplate.
|
||||
* The third is the inventory (composed of normal-type objects).
|
||||
* Rather than equipment other players would never interact with, it only comprises the contents of the five holster slots.<br>
|
||||
* <br>
|
||||
* If this player is spawned as dead - with their `health` at 0% - he will start standing and then immediately fall into a lying pose.
|
||||
* The death pose selected is randomized, can not be influenced, and is not be shared across clients.
|
||||
* @param appearance the player's cardinal appearance settings
|
||||
* In the "backend of the client," the character produced by this data is no different
|
||||
* from the kind of character that could be declared a given player's avatar.
|
||||
* In terms of equipment and complicated features common to an avatar character, however,
|
||||
* any user would find this character ill-equipped.
|
||||
* @param health the amount of health the player has, as a percentage of a filled bar;
|
||||
* the bar has 85 states, with 3 points for each state;
|
||||
* when 0% (less than 3 of 255), the player will collapse into a death pose on the ground
|
||||
|
|
@ -76,89 +66,69 @@ object UniformStyle extends Enumeration {
|
|||
* @param cosmetics optional decorative features that are added to the player's head model by console/chat commands;
|
||||
* they become available at battle rank 24, but here they require the third uniform upgrade (rank 25);
|
||||
* these flags do not exist if they are not applicable
|
||||
* @param inventory the avatar's inventory;
|
||||
* typically, only the tools and weapons in the equipment holster slots
|
||||
* @param drawn_slot the holster that is initially drawn;
|
||||
* defaults to `DrawnSlot.None`
|
||||
* @see `CharacterAppearanceData`
|
||||
* @see `DetailedCharacterData`
|
||||
* @see `InventoryData`
|
||||
* @see `DrawnSlot`
|
||||
*/
|
||||
final case class CharacterData(appearance : CharacterAppearanceData,
|
||||
health : Int,
|
||||
final case class CharacterData(health : Int,
|
||||
armor : Int,
|
||||
uniform_upgrade : UniformStyle.Value,
|
||||
unk : Int,
|
||||
command_rank : Int,
|
||||
implant_effects : Option[ImplantEffects.Value],
|
||||
cosmetics : Option[Cosmetics],
|
||||
inventory : Option[InventoryData],
|
||||
drawn_slot : DrawnSlot.Value = DrawnSlot.None
|
||||
) extends ConstructorData {
|
||||
cosmetics : Option[Cosmetics])
|
||||
(is_backpack : Boolean) extends ConstructorData {
|
||||
|
||||
override def bitsize : Long = {
|
||||
//factor guard bool values into the base size, not its corresponding optional field
|
||||
val appearanceSize : Long = appearance.bitsize
|
||||
val effectsSize : Long = if(implant_effects.isDefined) { 4L } else { 0L }
|
||||
val cosmeticsSize : Long = if(cosmetics.isDefined) { cosmetics.get.bitsize } else { 0L }
|
||||
val inventorySize : Long = if(inventory.isDefined) { inventory.get.bitsize } else { 0L }
|
||||
32L + appearanceSize + effectsSize + cosmeticsSize + inventorySize
|
||||
27L + effectsSize + cosmeticsSize
|
||||
}
|
||||
}
|
||||
|
||||
object CharacterData extends Marshallable[CharacterData] {
|
||||
/**
|
||||
* An overloaded constructor for `CharacterData` that allows for a not-optional inventory.
|
||||
* @param appearance the player's cardinal appearance settings
|
||||
* @param health the amount of health the player has, as a percentage of a filled bar
|
||||
* @param armor the amount of armor the player has, as a percentage of a filled bar
|
||||
* @param uniform the level of upgrade to apply to the player's base uniform
|
||||
* @param cr the player's command rank as a number from 0 to 5
|
||||
* @param implant_effects the effects of implants that can be seen on a player's character
|
||||
* @param cosmetics optional decorative features that are added to the player's head model by console/chat commands
|
||||
* @param inv the avatar's inventory
|
||||
* @param drawn_slot the holster that is initially drawn
|
||||
* //@param inv the avatar's inventory
|
||||
* //@param drawn_slot the holster that is initially drawn
|
||||
* @return a `CharacterData` object
|
||||
*/
|
||||
def apply(appearance : CharacterAppearanceData, health : Int, armor : Int, uniform : UniformStyle.Value, cr : Int, implant_effects : Option[ImplantEffects.Value], cosmetics : Option[Cosmetics], inv : InventoryData, drawn_slot : DrawnSlot.Value) : CharacterData =
|
||||
new CharacterData(appearance, health, armor, uniform, cr, implant_effects, cosmetics, Some(inv), drawn_slot)
|
||||
def apply(health : Int, armor : Int, uniform : UniformStyle.Value, cr : Int, implant_effects : Option[ImplantEffects.Value], cosmetics : Option[Cosmetics]) : (Boolean)=>CharacterData =
|
||||
CharacterData(health, armor, uniform, 0, cr, implant_effects, cosmetics)
|
||||
|
||||
implicit val codec : Codec[CharacterData] = (
|
||||
("app" | CharacterAppearanceData.codec) ::
|
||||
("health" | uint8L) :: //dead state when health == 0
|
||||
def codec(is_backpack : Boolean) : Codec[CharacterData] = (
|
||||
("health" | uint8L) :: //dead state when health == 0
|
||||
("armor" | uint8L) ::
|
||||
(("uniform_upgrade" | UniformStyle.codec) >>:~ { style =>
|
||||
ignore(3) :: //unknown
|
||||
("command_rank" | uintL(3)) ::
|
||||
bool :: //stream misalignment when != 1
|
||||
optional(bool, "implant_effects" | ImplantEffects.codec) ::
|
||||
conditional(style == UniformStyle.ThirdUpgrade, "cosmetics" | Cosmetics.codec) ::
|
||||
optional(bool, "inventory" | InventoryData.codec) ::
|
||||
("drawn_slot" | DrawnSlot.codec) ::
|
||||
bool //usually false
|
||||
conditional(style == UniformStyle.ThirdUpgrade, "cosmetics" | Cosmetics.codec)
|
||||
})
|
||||
).exmap[CharacterData] (
|
||||
).exmap[CharacterData] (
|
||||
{
|
||||
case app :: health :: armor :: uniform :: _ :: cr :: false :: implant_effects :: cosmetics :: inv :: drawn_slot :: false :: HNil =>
|
||||
var newHealth = health
|
||||
if(app.backpack) {
|
||||
newHealth = 0
|
||||
}
|
||||
Attempt.Successful(CharacterData(app, newHealth, armor, uniform, cr, implant_effects, cosmetics, inv, drawn_slot))
|
||||
case health :: armor :: uniform :: _ :: cr :: false :: implant_effects :: cosmetics :: HNil =>
|
||||
val newHealth = if(is_backpack) { 0 } else { health }
|
||||
Attempt.Successful(new CharacterData(newHealth, armor, uniform, 0, cr, implant_effects, cosmetics)(is_backpack))
|
||||
|
||||
case _ =>
|
||||
Attempt.Failure(Err("invalid character data; can not encode"))
|
||||
},
|
||||
{
|
||||
case CharacterData(app, health, armor, uniform, cr, implant_effects, cosmetics, inv, drawn_slot) =>
|
||||
var newHealth = health
|
||||
if(app.backpack) {
|
||||
newHealth = 0
|
||||
}
|
||||
Attempt.Successful(app :: newHealth :: armor :: uniform :: () :: cr :: false :: implant_effects :: cosmetics :: inv :: drawn_slot :: false :: HNil)
|
||||
case CharacterData(health, armor, uniform, _, cr, implant_effects, cosmetics) =>
|
||||
val newHealth = if(is_backpack) { 0 } else { health }
|
||||
Attempt.Successful(newHealth :: armor :: uniform :: () :: cr :: false :: implant_effects :: cosmetics :: HNil)
|
||||
|
||||
case _ =>
|
||||
Attempt.Failure(Err("invalid character data; can not decode"))
|
||||
}
|
||||
)
|
||||
|
||||
implicit val codec : Codec[CharacterData] = codec(false)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,22 +27,14 @@ final case class ImplantEntry(implant : ImplantType.Value,
|
|||
}
|
||||
|
||||
/**
|
||||
* A representation of the avatar portion of `ObjectCreateDetailedMessage` packet data.
|
||||
* This densely-packed information outlines most of the specifics required to depict a character as an avatar.<br>
|
||||
* A representation of a portion of an avatar's `ObjectCreateDetailedMessage` packet data.<br>
|
||||
* <br>
|
||||
* As an avatar, the character created by this data is expected to be controllable by the client that gets sent this data.
|
||||
* It goes into depth about information related to the given character in-game career that is not revealed to other players.<br>
|
||||
* <br>
|
||||
* Divisions exist to make the data more manageable.
|
||||
* The first division of data only manages the general appearance of the player's in-game model.
|
||||
* It is shared between `DetailedCharacterData` avatars and `CharacterData` player characters.
|
||||
* The second division (of fields) manages the status of the character as an avatar.
|
||||
* In general, it passes more thorough data about the character that the client can display to the owner of the client.
|
||||
* This densely-packed information outlines most of the specifics required to depict a character as an avatar.
|
||||
* It goes into depth about information related to the given character in-game career that is not revealed to other players.
|
||||
* To be specific, it passes more thorough data about the character that the client can display to the owner of the client.
|
||||
* For example, health is a full number, rather than a percentage.
|
||||
* Just as prominent is the list of first time events and the list of completed tutorials.
|
||||
* The third subdivision is also exclusive to avatar-prepared characters and contains (omitted).
|
||||
* The fourth is the inventory (composed of `Direct`-type objects).
|
||||
* @param appearance data about the avatar's basic aesthetics
|
||||
* Additionally, a full inventory, as opposed to the initial five weapon slots.
|
||||
* @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;
|
||||
|
|
@ -73,16 +65,10 @@ final case class ImplantEntry(implant : ImplantType.Value,
|
|||
* @param cosmetics optional decorative features that are added to the player's head model by console/chat commands;
|
||||
* they become available at battle rank 24;
|
||||
* these flags do not exist if they are not applicable
|
||||
* @param inventory the avatar's inventory
|
||||
* @param drawn_slot the holster that is initially drawn
|
||||
* @see `CharacterAppearanceData`<br>
|
||||
* `CharacterData`<br>
|
||||
* `CertificationType`<br>
|
||||
* `InventoryData`<br>
|
||||
* `DrawnSlot`
|
||||
* @see `CharacterData`<br>
|
||||
* `CertificationType`
|
||||
*/
|
||||
final case class DetailedCharacterData(appearance : CharacterAppearanceData,
|
||||
bep : Long,
|
||||
final case class DetailedCharacterData(bep : Long,
|
||||
cep : Long,
|
||||
healthMax : Int,
|
||||
health : Int,
|
||||
|
|
@ -96,20 +82,17 @@ final case class DetailedCharacterData(appearance : CharacterAppearanceData,
|
|||
implants : List[ImplantEntry],
|
||||
firstTimeEvents : List[String],
|
||||
tutorials : List[String],
|
||||
cosmetics : Option[Cosmetics],
|
||||
inventory : Option[InventoryData],
|
||||
drawn_slot : DrawnSlot.Value = DrawnSlot.None
|
||||
) extends ConstructorData {
|
||||
cosmetics : Option[Cosmetics])
|
||||
(pad_length : Option[Int]) extends ConstructorData {
|
||||
|
||||
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 certSize = (certs.length + 1) * 8 //cert list
|
||||
var implantSize : Long = 0L //implant list
|
||||
for(entry <- implants) {
|
||||
implantSize += entry.bitsize
|
||||
}
|
||||
val implantPadding = DetailedCharacterData.implantFieldPadding(implants, CharacterAppearanceData.altModelBit(appearance))
|
||||
val implantPadding = DetailedCharacterData.implantFieldPadding(implants, pad_length)
|
||||
val fteLen = firstTimeEvents.size //fte list
|
||||
var eventListSize : Long = 32L + DetailedCharacterData.ftePadding(fteLen, implantPadding)
|
||||
for(str <- firstTimeEvents) {
|
||||
|
|
@ -123,20 +106,13 @@ final case class DetailedCharacterData(appearance : CharacterAppearanceData,
|
|||
val br24 = DetailedCharacterData.isBR24(bep) //character is at least BR24
|
||||
val extraBitSize : Long = if(br24) { 33L } else { 46L }
|
||||
val cosmeticsSize : Long = if(br24) { cosmetics.get.bitsize } else { 0L }
|
||||
val inventorySize : Long = if(inventory.isDefined) { //inventory
|
||||
inventory.get.bitsize
|
||||
}
|
||||
else {
|
||||
0L
|
||||
}
|
||||
603L + appearanceSize + certSize + implantSize + eventListSize + extraBitSize + cosmeticsSize + tutorialListSize + inventorySize
|
||||
598L + certSize + implantSize + eventListSize + extraBitSize + cosmeticsSize + tutorialListSize
|
||||
}
|
||||
}
|
||||
|
||||
object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||
/**
|
||||
* 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
|
||||
|
|
@ -148,12 +124,10 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
|||
* @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, staminaMax : Int, stamina : Int, certs : List[CertificationType.Value], implants : List[ImplantEntry], firstTimeEvents : List[String], tutorials : List[String], cosmetics : Option[Cosmetics], inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedCharacterData =
|
||||
new DetailedCharacterData(appearance, bep, cep, healthMax, health, armor, 1, 7, 7, staminaMax, stamina, certs, implants, firstTimeEvents, tutorials, cosmetics, Some(inventory), drawn_slot)
|
||||
def apply(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], cosmetics : Option[Cosmetics]) : (Option[Int])=>DetailedCharacterData =
|
||||
DetailedCharacterData(bep, cep, healthMax, health, armor, 1, 7, 7, staminaMax, stamina, certs, implants, firstTimeEvents, tutorials, cosmetics)
|
||||
|
||||
/**
|
||||
* `Codec` for entries in the `List` of implants.
|
||||
|
|
@ -278,57 +252,52 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
|||
|
||||
def isBR24(bep : Long) : Boolean = bep > 2286230
|
||||
|
||||
implicit val codec : Codec[DetailedCharacterData] = (
|
||||
("appearance" | CharacterAppearanceData.codec) >>:~ { app =>
|
||||
("bep" | uint32L) >>:~ { bep =>
|
||||
("cep" | uint32L) ::
|
||||
ignore(96) ::
|
||||
("healthMax" | uint16L) ::
|
||||
("health" | uint16L) ::
|
||||
ignore(1) ::
|
||||
("armor" | uint16L) ::
|
||||
ignore(9) ::
|
||||
("unk1" | uint8L) ::
|
||||
ignore(8) ::
|
||||
("unk2" | uint4L) ::
|
||||
("unk3" | uintL(3)) ::
|
||||
("staminaMax" | uint16L) ::
|
||||
("stamina" | uint16L) ::
|
||||
ignore(147) ::
|
||||
("certs" | listOfN(uint8L, CertificationType.codec)) ::
|
||||
optional(bool, uint32L) :: //ask about sample CCRIDER
|
||||
ignore(4) ::
|
||||
(("implants" | PacketHelpers.listOfNSized(numberOfImplantSlots(bep), implant_entry_codec)) >>:~ { implants =>
|
||||
ignore(12) ::
|
||||
(("firstTimeEvent_length" | uint32L) >>:~ { len =>
|
||||
conditional(len > 0, "firstTimeEvent_firstEntry" | PacketHelpers.encodedStringAligned(ftePadding(len, implantFieldPadding(implants, CharacterAppearanceData.altModelBit(app))))) ::
|
||||
("firstTimeEvent_list" | PacketHelpers.listOfNSized(len - 1, PacketHelpers.encodedString)) ::
|
||||
(("tutorial_length" | uint32L) >>:~ { len2 =>
|
||||
conditional(len2 > 0, "tutorial_firstEntry" | PacketHelpers.encodedStringAligned(tutPadding(len, len2, implantFieldPadding(implants, CharacterAppearanceData.altModelBit(app))))) ::
|
||||
("tutorial_list" | PacketHelpers.listOfNSized(len2 - 1, PacketHelpers.encodedString)) ::
|
||||
ignore(160) ::
|
||||
(bool >>:~ { br24 => //BR24+
|
||||
newcodecs.binary_choice(br24, ignore(33), ignore(46)) ::
|
||||
conditional(br24, Cosmetics.codec) ::
|
||||
optional(bool, "inventory" | InventoryData.codec_detailed) ::
|
||||
("drawn_slot" | DrawnSlot.codec) ::
|
||||
bool //usually false
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
def codec(pad_length : Option[Int]) : Codec[DetailedCharacterData] = (
|
||||
("bep" | uint32L) >>:~ { bep =>
|
||||
("cep" | uint32L) ::
|
||||
ignore(96) ::
|
||||
("healthMax" | uint16L) ::
|
||||
("health" | uint16L) ::
|
||||
ignore(1) ::
|
||||
("armor" | uint16L) ::
|
||||
ignore(9) ::
|
||||
("unk1" | uint8L) ::
|
||||
ignore(8) ::
|
||||
("unk2" | uint4L) ::
|
||||
("unk3" | uintL(3)) ::
|
||||
("staminaMax" | uint16L) ::
|
||||
("stamina" | uint16L) ::
|
||||
ignore(147) ::
|
||||
("certs" | listOfN(uint8L, CertificationType.codec)) ::
|
||||
optional(bool, uint32L) :: //ask about sample CCRIDER
|
||||
ignore(4) ::
|
||||
(("implants" | PacketHelpers.listOfNSized(numberOfImplantSlots(bep), implant_entry_codec)) >>:~ { implants =>
|
||||
ignore(12) ::
|
||||
(("firstTimeEvent_length" | uint32L) >>:~ { len =>
|
||||
conditional(len > 0, "firstTimeEvent_firstEntry" | PacketHelpers.encodedStringAligned(ftePadding(len, implantFieldPadding(implants, pad_length)))) ::
|
||||
("firstTimeEvent_list" | PacketHelpers.listOfNSized(len - 1, PacketHelpers.encodedString)) ::
|
||||
(("tutorial_length" | uint32L) >>:~ { len2 =>
|
||||
conditional(len2 > 0, "tutorial_firstEntry" | PacketHelpers.encodedStringAligned(tutPadding(len, len2, implantFieldPadding(implants, pad_length)))) ::
|
||||
("tutorial_list" | PacketHelpers.listOfNSized(len2 - 1, PacketHelpers.encodedString)) ::
|
||||
ignore(160) ::
|
||||
(bool >>:~ { br24 => //BR24+
|
||||
newcodecs.binary_choice(br24, ignore(33), ignore(46)) ::
|
||||
conditional(br24, Cosmetics.codec)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
).exmap[DetailedCharacterData] (
|
||||
{
|
||||
case app :: bep :: cep :: _ :: hpmax :: hp :: _ :: armor :: _ :: u1 :: _ :: u2 :: u3 :: stamax :: stam :: _ :: certs :: _ :: _ :: implants :: _ :: _ :: fte0 :: fte1 :: _ :: tut0 :: tut1 :: _ :: _ :: _ :: cosmetics :: inv :: drawn :: false :: HNil =>
|
||||
case bep :: cep :: _ :: hpmax :: hp :: _ :: armor :: _ :: u1 :: _ :: u2 :: u3 :: stamax :: stam :: _ :: certs :: _ :: _ :: implants :: _ :: _ :: fte0 :: fte1 :: _ :: tut0 :: tut1 :: _ :: _ :: _ :: cosmetics :: HNil =>
|
||||
//prepend the displaced first elements to their lists
|
||||
val fteList : List[String] = if(fte0.isDefined) { fte0.get +: fte1 } else { fte1 }
|
||||
val tutList : List[String] = if(tut0.isDefined) { tut0.get +: tut1 } else { tut1 }
|
||||
Attempt.successful(DetailedCharacterData(app, bep, cep, hpmax, hp, armor, u1, u2, u3, stamax, stam, certs, implants, fteList, tutList, cosmetics, inv, drawn))
|
||||
Attempt.successful(DetailedCharacterData(bep, cep, hpmax, hp, armor, u1, u2, u3, stamax, stam, certs, implants, fteList, tutList, cosmetics)(pad_length))
|
||||
},
|
||||
{
|
||||
case DetailedCharacterData(app, bep, cep, hpmax, hp, armor, u1, u2, u3, stamax, stam, certs, implants, fteList, tutList, cos, inv, drawn) =>
|
||||
case DetailedCharacterData(bep, cep, hpmax, hp, armor, u1, u2, u3, stamax, stam, certs, implants, fteList, tutList, cos) =>
|
||||
val implantCapacity : Int = numberOfImplantSlots(bep)
|
||||
val implantList = if(implants.length > implantCapacity) {
|
||||
implants.slice(0, implantCapacity)
|
||||
|
|
@ -349,7 +318,9 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
|||
}
|
||||
val br24 : Boolean = isBR24(bep)
|
||||
val cosmetics : Option[Cosmetics] = if(br24) { cos } else { None }
|
||||
Attempt.successful(app :: bep :: cep :: () :: hpmax :: hp :: () :: armor :: () :: u1 :: () :: u2 :: u3 :: stamax :: stam :: () :: certs :: None :: () :: implantList :: () :: fteList.size.toLong :: firstEvent :: fteListCopy :: tutList.size.toLong :: firstTutorial :: tutListCopy :: () :: br24 :: () :: cosmetics :: inv :: drawn :: false :: HNil)
|
||||
Attempt.successful(bep :: cep :: () :: hpmax :: hp :: () :: armor :: () :: u1 :: () :: u2 :: u3 :: stamax :: stam :: () :: certs :: None :: () :: implantList :: () :: fteList.size.toLong :: firstEvent :: fteListCopy :: tutList.size.toLong :: firstTutorial :: tutListCopy :: () :: br24 :: () :: cosmetics :: HNil)
|
||||
}
|
||||
)
|
||||
|
||||
implicit val codec : Codec[DetailedCharacterData] = codec(None)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.packet.game.objectcreate
|
||||
|
||||
import net.psforever.packet.Marshallable
|
||||
import scodec.codecs._
|
||||
import scodec.Codec
|
||||
import shapeless.{::, HNil}
|
||||
|
||||
/**
|
||||
* A representation of an `avatar` player for the `ObjectCreateDetailedMessage` packet.
|
||||
* As an avatar, the character created by this data is expected to be controllable by the client that gets sent this data.<br>
|
||||
* <br>
|
||||
* Divisions exist to make the data more manageable.
|
||||
* The first division defines the player's location within the game coordinate system.
|
||||
* The second division defines features of the `avatar`
|
||||
* that are shared by both the `ObjectCreateDetailedMessage` version of a controlled player character (this)
|
||||
* and the `ObjectCreateMessage` version of a player character.
|
||||
* The third field expands on the nature of the character and this avatar's campaign.
|
||||
* Expansive information about previous interactions, the contents of their inventory, and equipment permissions are included.<br>
|
||||
* <br>
|
||||
* The presence or absence of position data as the first division creates a cascading effect
|
||||
* causing all of fields in the other two divisions to gain offsets.
|
||||
* These offsets exist in the form of `String` and `List` padding.
|
||||
* @see `DetailedCharacterData`<br>
|
||||
* `InventoryData`<br>
|
||||
* `DrawnSlot`
|
||||
* @param pos the optional position of the character in the world environment
|
||||
* @param basic_appearance common fields regarding the the character's appearance
|
||||
* @param character_data the class-specific data that explains about the character
|
||||
* @param position_defined used by the `Codec` to seed the state of the optional `pos` field
|
||||
* @param inventory the player's full inventory
|
||||
* @param drawn_slot the holster that is initially drawn
|
||||
*/
|
||||
final case class DetailedPlayerData(pos : Option[PlacementData],
|
||||
basic_appearance : CharacterAppearanceData,
|
||||
character_data : DetailedCharacterData,
|
||||
inventory : Option[InventoryData],
|
||||
drawn_slot : DrawnSlot.Value)
|
||||
(position_defined : Boolean) extends ConstructorData {
|
||||
override def bitsize : Long = {
|
||||
val posSize : Long = if(pos.isDefined) { pos.get.bitsize } else { 0 }
|
||||
val appSize : Long = basic_appearance.bitsize
|
||||
val charSize = character_data.bitsize
|
||||
val inventorySize : Long = if(inventory.isDefined) { inventory.get.bitsize } else { 0L }
|
||||
5L + posSize + appSize + charSize + inventorySize
|
||||
}
|
||||
}
|
||||
|
||||
object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||
/**
|
||||
* Overloaded constructor that ignores the coordinate information.
|
||||
* It passes information between the three major divisions for the purposes of offset calculations.
|
||||
* @param basic_appearance a curried function for the common fields regarding the the character's appearance
|
||||
* @param character_data a curried function for the class-specific data that explains about the character
|
||||
* @return a `DetailedPlayerData` object
|
||||
*/
|
||||
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
|
||||
val appearance = basic_appearance(0)
|
||||
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(false)
|
||||
}
|
||||
/** */
|
||||
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
|
||||
val appearance = basic_appearance(0)
|
||||
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), None, drawn_slot)(false)
|
||||
}
|
||||
/**
|
||||
* Overloaded constructor that includes the coordinate information.
|
||||
* It passes information between the three major divisions for the purposes of offset calculations.
|
||||
* @param basic_appearance a curried function for the common fields regarding the the character's appearance
|
||||
* @param character_data a curried function for the class-specific data that explains about the character
|
||||
* @return a `DetailedPlayerData` object
|
||||
*/
|
||||
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
|
||||
val appearance = basic_appearance(PlayerData.placementOffset(Some(pos)))
|
||||
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(true)
|
||||
}
|
||||
/** */
|
||||
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
|
||||
val appearance = basic_appearance(PlayerData.placementOffset(Some(pos)))
|
||||
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), None, drawn_slot)(true)
|
||||
}
|
||||
|
||||
def codec(position_defined : Boolean) : Codec[DetailedPlayerData] = (
|
||||
conditional(position_defined, "pos" | PlacementData.codec) >>:~ { pos =>
|
||||
("basic_appearance" | CharacterAppearanceData.codec(PlayerData.placementOffset(pos))) >>:~ { app =>
|
||||
("character_data" | DetailedCharacterData.codec(app.altModelBit)) ::
|
||||
optional(bool, "inventory" | InventoryData.codec_detailed) ::
|
||||
("drawn_slot" | DrawnSlot.codec) ::
|
||||
bool //usually false
|
||||
}
|
||||
}).xmap[DetailedPlayerData] (
|
||||
{
|
||||
case pos :: app :: data :: inv :: hand :: _ :: HNil =>
|
||||
DetailedPlayerData(pos, app, data, inv, hand)(pos.isDefined)
|
||||
},
|
||||
{
|
||||
case DetailedPlayerData(pos, app, data, inv, hand) =>
|
||||
pos :: app :: data :: inv :: hand :: false :: HNil
|
||||
}
|
||||
)
|
||||
|
||||
implicit val codec : Codec[DetailedPlayerData] = codec(false)
|
||||
}
|
||||
|
|
@ -666,7 +666,7 @@ object ObjectClass {
|
|||
case ObjectClass.advanced_ace => ConstructorData.genericCodec(DetailedACEData.codec, "advanced ace")
|
||||
case ObjectClass.boomer_trigger => ConstructorData.genericCodec(DetailedBoomerTriggerData.codec, "boomer trigger")
|
||||
//other
|
||||
case ObjectClass.avatar => ConstructorData.genericCodec(DetailedCharacterData.codec, "avatar")
|
||||
case ObjectClass.avatar => ConstructorData.genericCodec(DetailedPlayerData.codec(true), "avatar")
|
||||
case ObjectClass.locker_container => ConstructorData.genericCodec(DetailedLockerContainerData.codec, "locker container")
|
||||
|
||||
//failure case
|
||||
|
|
@ -953,6 +953,7 @@ object ObjectClass {
|
|||
//other
|
||||
case ObjectClass.ams_order_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal")
|
||||
case ObjectClass.ams_respawn_tube => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal")
|
||||
case ObjectClass.avatar => ConstructorData.genericCodec(PlayerData.codec(false), "avatar")
|
||||
case ObjectClass.bfr_rearm_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal")
|
||||
case ObjectClass.implant_terminal_interface => ConstructorData.genericCodec(CommonTerminalData.codec, "implant terminal")
|
||||
case ObjectClass.lodestar_repair_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal")
|
||||
|
|
@ -1268,7 +1269,7 @@ object ObjectClass {
|
|||
case ObjectClass.wasp => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle")
|
||||
//other
|
||||
case ObjectClass.ams_respawn_tube => DroppedItemData.genericCodec(CommonTerminalData.codec, "terminal")
|
||||
case ObjectClass.avatar => ConstructorData.genericCodec(CharacterData.codec, "avatar")
|
||||
case ObjectClass.avatar => ConstructorData.genericCodec(PlayerData.codec(true), "avatar")
|
||||
case ObjectClass.capture_flag => ConstructorData.genericCodec(CaptureFlagData.codec, "capture flag")
|
||||
case ObjectClass.implant_terminal_interface => ConstructorData.genericCodec(CommonTerminalData.codec, "implant terminal")
|
||||
case ObjectClass.locker_container => ConstructorData.genericCodec(LockerContainerData.codec, "locker container")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.packet.game.objectcreate
|
||||
|
||||
import net.psforever.packet.Marshallable
|
||||
import scodec.codecs._
|
||||
import scodec.Codec
|
||||
import shapeless.{::, HNil}
|
||||
|
||||
/**
|
||||
* A representation of another player's character for the `ObjectCreateDetailedMessage` packet.
|
||||
* In general, this packet is used to describe other players.<br>
|
||||
* <br>
|
||||
* Divisions exist to make the data more manageable.
|
||||
* The first division defines the player's location within the game coordinate system.
|
||||
* The second division defines features of the character
|
||||
* that are shared by both the `ObjectCreateDetailedMessage` version of a controlled player character
|
||||
* and the `ObjectCreateMessage` version of a player character (this).
|
||||
* The third field provides further information on the appearance of the player character, albeit condensed.
|
||||
* One of the most compact forms of a player character description is transcribed using this information.<br>
|
||||
* <br>
|
||||
* The presence or absence of position data as the first division creates a cascading effect
|
||||
* causing all of fields in the other two divisions to gain offsets.
|
||||
* These offsets exist in the form of `String` and `List` padding.
|
||||
* @see `CharacterData`<br>
|
||||
* `InventoryData`<br>
|
||||
* `DrawnSlot`
|
||||
* @param pos the optional position of the character in the world environment
|
||||
* @param basic_appearance common fields regarding the the character's appearance
|
||||
* @param character_data the class-specific data that explains about the character
|
||||
* @param inventory the player's inventory;
|
||||
* typically, only the tools and weapons in the equipment holster slots
|
||||
* @param drawn_slot the holster that is initially drawn
|
||||
* @param position_defined used by the `Codec` to seed the state of the optional `pos` field
|
||||
*/
|
||||
final case class PlayerData(pos : Option[PlacementData],
|
||||
basic_appearance : CharacterAppearanceData,
|
||||
character_data : CharacterData,
|
||||
inventory : Option[InventoryData],
|
||||
drawn_slot : DrawnSlot.Value)
|
||||
(position_defined : Boolean) extends ConstructorData {
|
||||
override def bitsize : Long = {
|
||||
val posSize : Long = if(pos.isDefined) { pos.get.bitsize } else { 0 }
|
||||
val appSize : Long = basic_appearance.bitsize
|
||||
val charSize = character_data.bitsize
|
||||
val inventorySize : Long = if(inventory.isDefined) { inventory.get.bitsize } else { 0L }
|
||||
5L + posSize + appSize + charSize + inventorySize
|
||||
}
|
||||
}
|
||||
|
||||
object PlayerData extends Marshallable[PlayerData] {
|
||||
/**
|
||||
* Overloaded constructor that ignores the coordinate information.
|
||||
* It passes information between the three major divisions for the purposes of offset calculations.
|
||||
* @param basic_appearance a curried function for the common fields regarding the the character's appearance
|
||||
* @param character_data a curried function for the class-specific data that explains about the character
|
||||
* @param inventory the player's inventory
|
||||
* @param drawn_slot the holster that is initially drawn
|
||||
* @return a `PlayerData` object
|
||||
*/
|
||||
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type) : PlayerData = {
|
||||
val appearance = basic_appearance(0)
|
||||
PlayerData(None, appearance, character_data(appearance.backpack), Some(inventory), drawn_slot)(false)
|
||||
}
|
||||
/** */
|
||||
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean)=>CharacterData, hand_held : DrawnSlot.Type) : PlayerData = {
|
||||
val appearance = basic_appearance(0)
|
||||
PlayerData(None, appearance, character_data(appearance.backpack), None, hand_held)(false)
|
||||
}
|
||||
/**
|
||||
* Overloaded constructor that includes the coordinate information.
|
||||
* It passes information between the three major divisions for the purposes of offset calculations.
|
||||
* @param pos the optional position of the character in the world environment
|
||||
* @param basic_appearance a curried function for the common fields regarding the the character's appearance
|
||||
* @param character_data a curried function for the class-specific data that explains about the character
|
||||
* @param inventory the player's inventory
|
||||
* @param drawn_slot the holster that is initially drawn
|
||||
* @return a `PlayerData` object
|
||||
*/
|
||||
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type) : PlayerData = {
|
||||
val appearance = basic_appearance( placementOffset(Some(pos)) )
|
||||
PlayerData(Some(pos), appearance, character_data(appearance.backpack), Some(inventory), drawn_slot)(true)
|
||||
}
|
||||
/** */
|
||||
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean)=>CharacterData, hand_held : DrawnSlot.Type) : PlayerData = {
|
||||
val appearance = basic_appearance( placementOffset(Some(pos)) )
|
||||
PlayerData(Some(pos), appearance, character_data(appearance.backpack), None, hand_held)(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the padding offset for a subsequent field given the existence of `PlacementData`.
|
||||
* The padding will always be a number 0-7.
|
||||
* @see `PlacemtnData`
|
||||
* @param pos the optional `PlacementData` object that creates the shift in bits
|
||||
* @return the pad length in bits
|
||||
*/
|
||||
def placementOffset(pos : Option[PlacementData]) : Int = {
|
||||
if(pos.isEmpty) {
|
||||
0
|
||||
}
|
||||
else if(pos.get.vel.isDefined) {
|
||||
2
|
||||
}
|
||||
else {
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
def codec(position_defined : Boolean) : Codec[PlayerData] = (
|
||||
conditional(position_defined, "pos" | PlacementData.codec) >>:~ { pos =>
|
||||
("basic_appearance" | CharacterAppearanceData.codec(placementOffset(pos))) >>:~ { app =>
|
||||
("character_data" | CharacterData.codec(app.backpack)) ::
|
||||
optional(bool, "inventory" | InventoryData.codec) ::
|
||||
("drawn_slot" | DrawnSlot.codec) ::
|
||||
bool //usually false
|
||||
}
|
||||
}).xmap[PlayerData] (
|
||||
{
|
||||
case pos :: app :: data :: inv :: hand :: _ :: HNil =>
|
||||
PlayerData(pos, app, data, inv, hand)(pos.isDefined)
|
||||
},
|
||||
{
|
||||
case PlayerData(pos, app, data, inv, hand) =>
|
||||
pos :: app :: data :: inv :: hand :: false :: HNil
|
||||
}
|
||||
)
|
||||
|
||||
implicit val codec : Codec[PlayerData] = codec(false)
|
||||
}
|
||||
|
|
@ -20,93 +20,92 @@ class CharacterDataTest extends Specification {
|
|||
cls mustEqual ObjectClass.avatar
|
||||
guid mustEqual PlanetSideGUID(3902)
|
||||
parent.isDefined mustEqual false
|
||||
data.isDefined mustEqual true
|
||||
data.get.isInstanceOf[CharacterData] mustEqual true
|
||||
val pc = data.get.asInstanceOf[CharacterData]
|
||||
pc.appearance.pos.coord.x mustEqual 3674.8438f
|
||||
pc.appearance.pos.coord.y mustEqual 2726.789f
|
||||
pc.appearance.pos.coord.z mustEqual 91.15625f
|
||||
pc.appearance.pos.orient.x mustEqual 0f
|
||||
pc.appearance.pos.orient.y mustEqual 0f
|
||||
pc.appearance.pos.orient.z mustEqual 64.6875f
|
||||
pc.appearance.pos.vel.isDefined mustEqual true
|
||||
pc.appearance.pos.vel.get.x mustEqual 1.4375f
|
||||
pc.appearance.pos.vel.get.y mustEqual -0.4375f
|
||||
pc.appearance.pos.vel.get.z mustEqual 0f
|
||||
pc.appearance.basic_appearance.name mustEqual "ScrawnyRonnie"
|
||||
pc.appearance.basic_appearance.faction mustEqual PlanetSideEmpire.TR
|
||||
pc.appearance.basic_appearance.sex mustEqual CharacterGender.Male
|
||||
pc.appearance.basic_appearance.head mustEqual 5
|
||||
pc.appearance.basic_appearance.voice mustEqual 5
|
||||
pc.appearance.voice2 mustEqual 3
|
||||
pc.appearance.black_ops mustEqual false
|
||||
pc.appearance.jammered mustEqual false
|
||||
pc.appearance.exosuit mustEqual ExoSuitType.Reinforced
|
||||
pc.appearance.outfit_name mustEqual "Black Beret Armoured Corps"
|
||||
pc.appearance.outfit_logo mustEqual 23
|
||||
pc.appearance.facingPitch mustEqual 340.3125f
|
||||
pc.appearance.facingYawUpper mustEqual 0
|
||||
pc.appearance.lfs mustEqual false
|
||||
pc.appearance.grenade_state mustEqual GrenadeState.None
|
||||
pc.appearance.is_cloaking mustEqual false
|
||||
pc.appearance.charging_pose mustEqual false
|
||||
pc.appearance.on_zipline mustEqual false
|
||||
pc.appearance.ribbons.upper mustEqual MeritCommendation.MarkovVeteran
|
||||
pc.appearance.ribbons.middle mustEqual MeritCommendation.HeavyInfantry4
|
||||
pc.appearance.ribbons.lower mustEqual MeritCommendation.TankBuster7
|
||||
pc.appearance.ribbons.tos mustEqual MeritCommendation.SixYearTR
|
||||
pc.health mustEqual 255
|
||||
pc.armor mustEqual 253
|
||||
pc.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade
|
||||
pc.command_rank mustEqual 5
|
||||
pc.implant_effects.isDefined mustEqual true
|
||||
pc.implant_effects.get mustEqual ImplantEffects.NoEffects
|
||||
pc.cosmetics.isDefined mustEqual true
|
||||
pc.cosmetics.get.no_helmet mustEqual true
|
||||
pc.cosmetics.get.beret mustEqual true
|
||||
pc.cosmetics.get.sunglasses mustEqual true
|
||||
pc.cosmetics.get.earpiece mustEqual true
|
||||
pc.cosmetics.get.brimmed_cap mustEqual false
|
||||
//short test of inventory items
|
||||
pc.inventory.isDefined mustEqual true
|
||||
val contents = pc.inventory.get.contents
|
||||
contents.size mustEqual 5
|
||||
//0
|
||||
contents.head.objectClass mustEqual ObjectClass.plasma_grenade
|
||||
contents.head.guid mustEqual PlanetSideGUID(3662)
|
||||
contents.head.parentSlot mustEqual 0
|
||||
contents.head.obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
|
||||
contents.head.obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.plasma_grenade_ammo
|
||||
contents.head.obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3751)
|
||||
//1
|
||||
contents(1).objectClass mustEqual ObjectClass.bank
|
||||
contents(1).guid mustEqual PlanetSideGUID(3908)
|
||||
contents(1).parentSlot mustEqual 1
|
||||
contents(1).obj.asInstanceOf[WeaponData].fire_mode mustEqual 1
|
||||
contents(1).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.armor_canister
|
||||
contents(1).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(4143)
|
||||
//2
|
||||
contents(2).objectClass mustEqual ObjectClass.mini_chaingun
|
||||
contents(2).guid mustEqual PlanetSideGUID(4164)
|
||||
contents(2).parentSlot mustEqual 2
|
||||
contents(2).obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
|
||||
contents(2).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.bullet_9mm
|
||||
contents(2).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3728)
|
||||
//3
|
||||
contents(3).objectClass mustEqual ObjectClass.phoenix //actually, a decimator
|
||||
contents(3).guid mustEqual PlanetSideGUID(3603)
|
||||
contents(3).parentSlot mustEqual 3
|
||||
contents(3).obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
|
||||
contents(3).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.phoenix_missile
|
||||
contents(3).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3056)
|
||||
//4
|
||||
contents(4).objectClass mustEqual ObjectClass.chainblade
|
||||
contents(4).guid mustEqual PlanetSideGUID(4088)
|
||||
contents(4).parentSlot mustEqual 4
|
||||
contents(4).obj.asInstanceOf[WeaponData].fire_mode mustEqual 1
|
||||
contents(4).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.melee_ammo
|
||||
contents(4).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3279)
|
||||
pc.drawn_slot mustEqual DrawnSlot.Rifle1
|
||||
data match {
|
||||
case Some(PlayerData(Some(pos), basic, char, inv, hand)) =>
|
||||
pos.coord mustEqual Vector3(3674.8438f, 2726.789f, 91.15625f)
|
||||
pos.orient mustEqual Vector3(0f, 0f, 64.6875f)
|
||||
pos.vel.isDefined mustEqual true
|
||||
pos.vel.get mustEqual Vector3(1.4375f, -0.4375f, 0f)
|
||||
|
||||
basic.app.name mustEqual "ScrawnyRonnie"
|
||||
basic.app.faction mustEqual PlanetSideEmpire.TR
|
||||
basic.app.sex mustEqual CharacterGender.Male
|
||||
basic.app.head mustEqual 5
|
||||
basic.app.voice mustEqual 5
|
||||
basic.voice2 mustEqual 3
|
||||
basic.black_ops mustEqual false
|
||||
basic.jammered mustEqual false
|
||||
basic.exosuit mustEqual ExoSuitType.Reinforced
|
||||
basic.outfit_name mustEqual "Black Beret Armoured Corps"
|
||||
basic.outfit_logo mustEqual 23
|
||||
basic.facingPitch mustEqual 340.3125f
|
||||
basic.facingYawUpper mustEqual 0
|
||||
basic.lfs mustEqual false
|
||||
basic.grenade_state mustEqual GrenadeState.None
|
||||
basic.is_cloaking mustEqual false
|
||||
basic.charging_pose mustEqual false
|
||||
basic.on_zipline mustEqual false
|
||||
basic.ribbons.upper mustEqual MeritCommendation.MarkovVeteran
|
||||
basic.ribbons.middle mustEqual MeritCommendation.HeavyInfantry4
|
||||
basic.ribbons.lower mustEqual MeritCommendation.TankBuster7
|
||||
basic.ribbons.tos mustEqual MeritCommendation.SixYearTR
|
||||
|
||||
char.health mustEqual 255
|
||||
char.armor mustEqual 253
|
||||
char.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade
|
||||
char.command_rank mustEqual 5
|
||||
char.implant_effects.isDefined mustEqual true
|
||||
char.implant_effects.get mustEqual ImplantEffects.NoEffects
|
||||
char.cosmetics.isDefined mustEqual true
|
||||
char.cosmetics.get.no_helmet mustEqual true
|
||||
char.cosmetics.get.beret mustEqual true
|
||||
char.cosmetics.get.sunglasses mustEqual true
|
||||
char.cosmetics.get.earpiece mustEqual true
|
||||
char.cosmetics.get.brimmed_cap mustEqual false
|
||||
//short test of inventory items
|
||||
inv.isDefined mustEqual true
|
||||
val contents = inv.get.contents
|
||||
contents.size mustEqual 5
|
||||
//0
|
||||
contents.head.objectClass mustEqual ObjectClass.plasma_grenade
|
||||
contents.head.guid mustEqual PlanetSideGUID(3662)
|
||||
contents.head.parentSlot mustEqual 0
|
||||
contents.head.obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
|
||||
contents.head.obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.plasma_grenade_ammo
|
||||
contents.head.obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3751)
|
||||
//1
|
||||
contents(1).objectClass mustEqual ObjectClass.bank
|
||||
contents(1).guid mustEqual PlanetSideGUID(3908)
|
||||
contents(1).parentSlot mustEqual 1
|
||||
contents(1).obj.asInstanceOf[WeaponData].fire_mode mustEqual 1
|
||||
contents(1).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.armor_canister
|
||||
contents(1).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(4143)
|
||||
//2
|
||||
contents(2).objectClass mustEqual ObjectClass.mini_chaingun
|
||||
contents(2).guid mustEqual PlanetSideGUID(4164)
|
||||
contents(2).parentSlot mustEqual 2
|
||||
contents(2).obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
|
||||
contents(2).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.bullet_9mm
|
||||
contents(2).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3728)
|
||||
//3
|
||||
contents(3).objectClass mustEqual ObjectClass.phoenix //actually, a decimator
|
||||
contents(3).guid mustEqual PlanetSideGUID(3603)
|
||||
contents(3).parentSlot mustEqual 3
|
||||
contents(3).obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
|
||||
contents(3).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.phoenix_missile
|
||||
contents(3).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3056)
|
||||
//4
|
||||
contents(4).objectClass mustEqual ObjectClass.chainblade
|
||||
contents(4).guid mustEqual PlanetSideGUID(4088)
|
||||
contents(4).parentSlot mustEqual 4
|
||||
contents(4).obj.asInstanceOf[WeaponData].fire_mode mustEqual 1
|
||||
contents(4).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.melee_ammo
|
||||
contents(4).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3279)
|
||||
|
||||
hand mustEqual DrawnSlot.Rifle1
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
|
|
@ -119,104 +118,105 @@ class CharacterDataTest extends Specification {
|
|||
cls mustEqual ObjectClass.avatar
|
||||
guid mustEqual PlanetSideGUID(3380)
|
||||
parent.isDefined mustEqual false
|
||||
data.isDefined mustEqual true
|
||||
data.get.isInstanceOf[CharacterData] mustEqual true
|
||||
val pc = data.get.asInstanceOf[CharacterData]
|
||||
pc.appearance.pos.coord.x mustEqual 4629.8906f
|
||||
pc.appearance.pos.coord.y mustEqual 6316.4453f
|
||||
pc.appearance.pos.coord.z mustEqual 54.734375f
|
||||
pc.appearance.pos.orient.x mustEqual 0f
|
||||
pc.appearance.pos.orient.y mustEqual 0f
|
||||
pc.appearance.pos.orient.z mustEqual 126.5625f
|
||||
pc.appearance.pos.vel.isDefined mustEqual false
|
||||
pc.appearance.basic_appearance.name mustEqual "Angello"
|
||||
pc.appearance.basic_appearance.faction mustEqual PlanetSideEmpire.VS
|
||||
pc.appearance.basic_appearance.sex mustEqual CharacterGender.Male
|
||||
pc.appearance.basic_appearance.head mustEqual 10
|
||||
pc.appearance.basic_appearance.voice mustEqual 2
|
||||
pc.appearance.voice2 mustEqual 0
|
||||
pc.appearance.black_ops mustEqual false
|
||||
pc.appearance.jammered mustEqual false
|
||||
pc.appearance.exosuit mustEqual ExoSuitType.MAX
|
||||
pc.appearance.outfit_name mustEqual "Original District"
|
||||
pc.appearance.outfit_logo mustEqual 23
|
||||
pc.appearance.facingPitch mustEqual 0
|
||||
pc.appearance.facingYawUpper mustEqual 180.0f
|
||||
pc.appearance.lfs mustEqual false
|
||||
pc.appearance.grenade_state mustEqual GrenadeState.None
|
||||
pc.appearance.is_cloaking mustEqual false
|
||||
pc.appearance.charging_pose mustEqual false
|
||||
pc.appearance.on_zipline mustEqual false
|
||||
pc.appearance.ribbons.upper mustEqual MeritCommendation.Jacking2
|
||||
pc.appearance.ribbons.middle mustEqual MeritCommendation.ScavengerVS1
|
||||
pc.appearance.ribbons.lower mustEqual MeritCommendation.AMSSupport4
|
||||
pc.appearance.ribbons.tos mustEqual MeritCommendation.SixYearVS
|
||||
pc.health mustEqual 0
|
||||
pc.armor mustEqual 0
|
||||
pc.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade
|
||||
pc.command_rank mustEqual 2
|
||||
pc.implant_effects.isDefined mustEqual false
|
||||
pc.cosmetics.isDefined mustEqual true
|
||||
pc.cosmetics.get.no_helmet mustEqual true
|
||||
pc.cosmetics.get.beret mustEqual true
|
||||
pc.cosmetics.get.sunglasses mustEqual true
|
||||
pc.cosmetics.get.earpiece mustEqual true
|
||||
pc.cosmetics.get.brimmed_cap mustEqual false
|
||||
pc.inventory.isDefined mustEqual false
|
||||
pc.drawn_slot mustEqual DrawnSlot.Pistol1
|
||||
data match {
|
||||
case Some(PlayerData(Some(pos), basic, char, None, hand)) =>
|
||||
pos.coord mustEqual Vector3(4629.8906f, 6316.4453f, 54.734375f)
|
||||
pos.orient mustEqual Vector3(0, 0, 126.5625f)
|
||||
pos.vel.isDefined mustEqual false
|
||||
|
||||
basic.app.name mustEqual "Angello"
|
||||
basic.app.faction mustEqual PlanetSideEmpire.VS
|
||||
basic.app.sex mustEqual CharacterGender.Male
|
||||
basic.app.head mustEqual 10
|
||||
basic.app.voice mustEqual 2
|
||||
basic.voice2 mustEqual 0
|
||||
basic.black_ops mustEqual false
|
||||
basic.jammered mustEqual false
|
||||
basic.exosuit mustEqual ExoSuitType.MAX
|
||||
basic.outfit_name mustEqual "Original District"
|
||||
basic.outfit_logo mustEqual 23
|
||||
basic.facingPitch mustEqual 0
|
||||
basic.facingYawUpper mustEqual 180.0f
|
||||
basic.lfs mustEqual false
|
||||
basic.grenade_state mustEqual GrenadeState.None
|
||||
basic.is_cloaking mustEqual false
|
||||
basic.charging_pose mustEqual false
|
||||
basic.on_zipline mustEqual false
|
||||
basic.ribbons.upper mustEqual MeritCommendation.Jacking2
|
||||
basic.ribbons.middle mustEqual MeritCommendation.ScavengerVS1
|
||||
basic.ribbons.lower mustEqual MeritCommendation.AMSSupport4
|
||||
basic.ribbons.tos mustEqual MeritCommendation.SixYearVS
|
||||
|
||||
char.health mustEqual 0
|
||||
char.armor mustEqual 0
|
||||
char.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade
|
||||
char.command_rank mustEqual 2
|
||||
char.implant_effects.isDefined mustEqual false
|
||||
char.cosmetics.isDefined mustEqual true
|
||||
char.cosmetics.get.no_helmet mustEqual true
|
||||
char.cosmetics.get.beret mustEqual true
|
||||
char.cosmetics.get.sunglasses mustEqual true
|
||||
char.cosmetics.get.earpiece mustEqual true
|
||||
char.cosmetics.get.brimmed_cap mustEqual false
|
||||
|
||||
hand mustEqual DrawnSlot.Pistol1
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"encode" in {
|
||||
val obj = CharacterData(
|
||||
CharacterAppearanceData(
|
||||
PlacementData(
|
||||
Vector3(3674.8438f, 2726.789f, 91.15625f),
|
||||
Vector3(0f, 0f, 64.6875f),
|
||||
Some(Vector3(1.4375f, -0.4375f, 0f))
|
||||
),
|
||||
BasicCharacterData(
|
||||
"ScrawnyRonnie",
|
||||
PlanetSideEmpire.TR,
|
||||
CharacterGender.Male,
|
||||
5,
|
||||
5
|
||||
),
|
||||
3,
|
||||
false,
|
||||
false,
|
||||
ExoSuitType.Reinforced,
|
||||
"Black Beret Armoured Corps",
|
||||
23,
|
||||
false,
|
||||
340.3125f, 0f,
|
||||
false,
|
||||
GrenadeState.None,
|
||||
false, false, false,
|
||||
RibbonBars(
|
||||
MeritCommendation.MarkovVeteran,
|
||||
MeritCommendation.HeavyInfantry4,
|
||||
MeritCommendation.TankBuster7,
|
||||
MeritCommendation.SixYearTR
|
||||
)
|
||||
val pos : PlacementData = PlacementData(
|
||||
Vector3(3674.8438f, 2726.789f, 91.15625f),
|
||||
Vector3(0f, 0f, 64.6875f),
|
||||
Some(Vector3(1.4375f, -0.4375f, 0f))
|
||||
)
|
||||
val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData(
|
||||
BasicCharacterData(
|
||||
"ScrawnyRonnie",
|
||||
PlanetSideEmpire.TR,
|
||||
CharacterGender.Male,
|
||||
5,
|
||||
5
|
||||
),
|
||||
3,
|
||||
false,
|
||||
false,
|
||||
ExoSuitType.Reinforced,
|
||||
"Black Beret Armoured Corps",
|
||||
23,
|
||||
false,
|
||||
340.3125f, 0f,
|
||||
false,
|
||||
GrenadeState.None,
|
||||
false, false, false,
|
||||
RibbonBars(
|
||||
MeritCommendation.MarkovVeteran,
|
||||
MeritCommendation.HeavyInfantry4,
|
||||
MeritCommendation.TankBuster7,
|
||||
MeritCommendation.SixYearTR
|
||||
)
|
||||
)
|
||||
val char : (Boolean)=>CharacterData = CharacterData(
|
||||
255, 253,
|
||||
UniformStyle.ThirdUpgrade,
|
||||
5,
|
||||
Some(ImplantEffects.NoEffects),
|
||||
Some(Cosmetics(true, true, true, true, false)),
|
||||
InventoryData(
|
||||
InventoryItemData(ObjectClass.plasma_grenade, PlanetSideGUID(3662), 0, WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, AmmoBoxData())) ::
|
||||
InventoryItemData(ObjectClass.bank, PlanetSideGUID(3908), 1, WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, AmmoBoxData())) ::
|
||||
InventoryItemData(ObjectClass.mini_chaingun, PlanetSideGUID(4164), 2, WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, AmmoBoxData())) ::
|
||||
InventoryItemData(ObjectClass.phoenix, PlanetSideGUID(3603), 3, WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, AmmoBoxData())) ::
|
||||
InventoryItemData(ObjectClass.chainblade, PlanetSideGUID(4088), 4, WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, AmmoBoxData())) ::
|
||||
Nil
|
||||
),
|
||||
DrawnSlot.Rifle1
|
||||
Some(Cosmetics(true, true, true, true, false))
|
||||
)
|
||||
val inv = InventoryData(
|
||||
InventoryItemData(ObjectClass.plasma_grenade, PlanetSideGUID(3662), 0, WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, AmmoBoxData())) ::
|
||||
InventoryItemData(ObjectClass.bank, PlanetSideGUID(3908), 1, WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, AmmoBoxData())) ::
|
||||
InventoryItemData(ObjectClass.mini_chaingun, PlanetSideGUID(4164), 2, WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, AmmoBoxData())) ::
|
||||
InventoryItemData(ObjectClass.phoenix, PlanetSideGUID(3603), 3, WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, AmmoBoxData())) ::
|
||||
InventoryItemData(ObjectClass.chainblade, PlanetSideGUID(4088), 4, WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, AmmoBoxData())) ::
|
||||
Nil
|
||||
)
|
||||
val obj = PlayerData.apply(pos, app, char, inv, DrawnSlot.Rifle1)
|
||||
|
||||
val msg = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(3902), obj)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
val pkt_bitv = pkt.toBitVector
|
||||
|
|
@ -230,42 +230,45 @@ class CharacterDataTest extends Specification {
|
|||
}
|
||||
|
||||
"encode (backpack)" in {
|
||||
val obj = CharacterData(
|
||||
CharacterAppearanceData(
|
||||
PlacementData(4629.8906f, 6316.4453f, 54.734375f, 0f, 0f, 126.5625f),
|
||||
BasicCharacterData(
|
||||
"Angello",
|
||||
PlanetSideEmpire.VS,
|
||||
CharacterGender.Male,
|
||||
10,
|
||||
2
|
||||
),
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
ExoSuitType.MAX,
|
||||
"Original District",
|
||||
23,
|
||||
true, //backpack
|
||||
0f, 180.0f,
|
||||
false,
|
||||
GrenadeState.None,
|
||||
false, false, false,
|
||||
RibbonBars(
|
||||
MeritCommendation.Jacking2,
|
||||
MeritCommendation.ScavengerVS1,
|
||||
MeritCommendation.AMSSupport4,
|
||||
MeritCommendation.SixYearVS
|
||||
)
|
||||
val pos = PlacementData(
|
||||
Vector3(4629.8906f, 6316.4453f, 54.734375f),
|
||||
Vector3(0, 0, 126.5625f)
|
||||
)
|
||||
val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData(
|
||||
BasicCharacterData(
|
||||
"Angello",
|
||||
PlanetSideEmpire.VS,
|
||||
CharacterGender.Male,
|
||||
10,
|
||||
2
|
||||
),
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
ExoSuitType.MAX,
|
||||
"Original District",
|
||||
23,
|
||||
true, //backpack
|
||||
0f, 180.0f,
|
||||
false,
|
||||
GrenadeState.None,
|
||||
false, false, false,
|
||||
RibbonBars(
|
||||
MeritCommendation.Jacking2,
|
||||
MeritCommendation.ScavengerVS1,
|
||||
MeritCommendation.AMSSupport4,
|
||||
MeritCommendation.SixYearVS
|
||||
)
|
||||
)
|
||||
val char : (Boolean)=>CharacterData = CharacterData(
|
||||
0, 0,
|
||||
UniformStyle.ThirdUpgrade,
|
||||
2,
|
||||
None,
|
||||
Some(Cosmetics(true, true, true, true, false)),
|
||||
None,
|
||||
DrawnSlot.Pistol1
|
||||
Some(Cosmetics(true, true, true, true, false))
|
||||
)
|
||||
val obj = PlayerData.apply(pos, app, char, DrawnSlot.Pistol1)
|
||||
|
||||
val msg = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(3380), obj)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
val pkt_bitv = pkt.toBitVector
|
||||
|
|
|
|||
|
|
@ -20,130 +20,132 @@ class DetailedCharacterDataTest extends Specification {
|
|||
cls mustEqual ObjectClass.avatar
|
||||
guid mustEqual PlanetSideGUID(75)
|
||||
parent.isDefined mustEqual false
|
||||
data.isDefined mustEqual true
|
||||
val char = data.get.asInstanceOf[DetailedCharacterData]
|
||||
char.appearance.pos.coord.x mustEqual 3674.8438f
|
||||
char.appearance.pos.coord.y mustEqual 2726.789f
|
||||
char.appearance.pos.coord.z mustEqual 91.15625f
|
||||
char.appearance.pos.orient.x mustEqual 0
|
||||
char.appearance.pos.orient.y mustEqual 0f
|
||||
char.appearance.pos.orient.z mustEqual 36.5625f
|
||||
char.appearance.basic_appearance.name mustEqual "IlllIIIlllIlIllIlllIllI"
|
||||
char.appearance.basic_appearance.faction mustEqual PlanetSideEmpire.VS
|
||||
char.appearance.basic_appearance.sex mustEqual CharacterGender.Female
|
||||
char.appearance.basic_appearance.head mustEqual 41
|
||||
char.appearance.basic_appearance.voice mustEqual 1 //female 1
|
||||
char.appearance.voice2 mustEqual 3
|
||||
char.appearance.black_ops mustEqual false
|
||||
char.appearance.jammered mustEqual false
|
||||
char.appearance.exosuit mustEqual ExoSuitType.Standard
|
||||
char.appearance.outfit_name mustEqual ""
|
||||
char.appearance.outfit_logo mustEqual 0
|
||||
char.appearance.backpack mustEqual false
|
||||
char.appearance.facingPitch mustEqual 2.8125f
|
||||
char.appearance.facingYawUpper mustEqual 210.9375f
|
||||
char.appearance.lfs mustEqual true
|
||||
char.appearance.grenade_state mustEqual GrenadeState.None
|
||||
char.appearance.is_cloaking mustEqual false
|
||||
char.appearance.charging_pose mustEqual false
|
||||
char.appearance.on_zipline mustEqual false
|
||||
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.bep mustEqual 0
|
||||
char.cep mustEqual 0
|
||||
char.healthMax mustEqual 100
|
||||
char.health mustEqual 100
|
||||
char.armor mustEqual 50 //standard exosuit value
|
||||
char.unk1 mustEqual 1
|
||||
char.unk2 mustEqual 7
|
||||
char.unk3 mustEqual 7
|
||||
char.staminaMax mustEqual 100
|
||||
char.stamina mustEqual 100
|
||||
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"
|
||||
char.firstTimeEvents(2) mustEqual "used_beamer"
|
||||
char.firstTimeEvents(3) mustEqual "map13"
|
||||
char.tutorials.size mustEqual 0
|
||||
char.cosmetics.isDefined mustEqual false
|
||||
char.inventory.isDefined mustEqual true
|
||||
val inventory = char.inventory.get.contents
|
||||
inventory.size mustEqual 10
|
||||
//0
|
||||
inventory.head.objectClass mustEqual ObjectClass.beamer
|
||||
inventory.head.guid mustEqual PlanetSideGUID(76)
|
||||
inventory.head.parentSlot mustEqual 0
|
||||
var wep = inventory.head.obj.asInstanceOf[DetailedWeaponData]
|
||||
wep.ammo.head.objectClass mustEqual ObjectClass.energy_cell
|
||||
wep.ammo.head.guid mustEqual PlanetSideGUID(77)
|
||||
wep.ammo.head.parentSlot mustEqual 0
|
||||
wep.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 16
|
||||
//1
|
||||
inventory(1).objectClass mustEqual ObjectClass.suppressor
|
||||
inventory(1).guid mustEqual PlanetSideGUID(78)
|
||||
inventory(1).parentSlot mustEqual 2
|
||||
wep = inventory(1).obj.asInstanceOf[DetailedWeaponData]
|
||||
wep.ammo.head.objectClass mustEqual ObjectClass.bullet_9mm
|
||||
wep.ammo.head.guid mustEqual PlanetSideGUID(79)
|
||||
wep.ammo.head.parentSlot mustEqual 0
|
||||
wep.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 25
|
||||
//2
|
||||
inventory(2).objectClass mustEqual ObjectClass.forceblade
|
||||
inventory(2).guid mustEqual PlanetSideGUID(80)
|
||||
inventory(2).parentSlot mustEqual 4
|
||||
wep = inventory(2).obj.asInstanceOf[DetailedWeaponData]
|
||||
wep.ammo.head.objectClass mustEqual ObjectClass.melee_ammo
|
||||
wep.ammo.head.guid mustEqual PlanetSideGUID(81)
|
||||
wep.ammo.head.parentSlot mustEqual 0
|
||||
wep.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 1
|
||||
//3
|
||||
inventory(3).objectClass mustEqual ObjectClass.locker_container
|
||||
inventory(3).guid mustEqual PlanetSideGUID(82)
|
||||
inventory(3).parentSlot mustEqual 5
|
||||
inventory(3).obj.isInstanceOf[DetailedLockerContainerData] mustEqual true
|
||||
inventory(3).obj.asInstanceOf[DetailedLockerContainerData].inventory.isDefined mustEqual false
|
||||
//4
|
||||
inventory(4).objectClass mustEqual ObjectClass.bullet_9mm
|
||||
inventory(4).guid mustEqual PlanetSideGUID(83)
|
||||
inventory(4).parentSlot mustEqual 6
|
||||
inventory(4).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
|
||||
//5
|
||||
inventory(5).objectClass mustEqual ObjectClass.bullet_9mm
|
||||
inventory(5).guid mustEqual PlanetSideGUID(84)
|
||||
inventory(5).parentSlot mustEqual 9
|
||||
inventory(5).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
|
||||
//6
|
||||
inventory(6).objectClass mustEqual ObjectClass.bullet_9mm
|
||||
inventory(6).guid mustEqual PlanetSideGUID(85)
|
||||
inventory(6).parentSlot mustEqual 12
|
||||
inventory(6).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
|
||||
//7
|
||||
inventory(7).objectClass mustEqual ObjectClass.bullet_9mm_AP
|
||||
inventory(7).guid mustEqual PlanetSideGUID(86)
|
||||
inventory(7).parentSlot mustEqual 33
|
||||
inventory(7).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
|
||||
//8
|
||||
inventory(8).objectClass mustEqual ObjectClass.energy_cell
|
||||
inventory(8).guid mustEqual PlanetSideGUID(87)
|
||||
inventory(8).parentSlot mustEqual 36
|
||||
inventory(8).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
|
||||
//9
|
||||
inventory(9).objectClass mustEqual ObjectClass.remote_electronics_kit
|
||||
inventory(9).guid mustEqual PlanetSideGUID(88)
|
||||
inventory(9).parentSlot mustEqual 39
|
||||
//the rek has data but none worth testing here
|
||||
char.drawn_slot mustEqual DrawnSlot.Pistol1
|
||||
data match {
|
||||
case Some(DetailedPlayerData(Some(pos), basic, char, inv, hand)) =>
|
||||
pos.coord mustEqual Vector3(3674.8438f, 2726.789f, 91.15625f)
|
||||
pos.orient mustEqual Vector3(0, 0, 36.5625f)
|
||||
pos.vel.isDefined mustEqual false
|
||||
|
||||
basic.app.name mustEqual "IlllIIIlllIlIllIlllIllI"
|
||||
basic.app.faction mustEqual PlanetSideEmpire.VS
|
||||
basic.app.sex mustEqual CharacterGender.Female
|
||||
basic.app.head mustEqual 41
|
||||
basic.app.voice mustEqual 1 //female 1
|
||||
basic.voice2 mustEqual 3
|
||||
basic.black_ops mustEqual false
|
||||
basic.jammered mustEqual false
|
||||
basic.exosuit mustEqual ExoSuitType.Standard
|
||||
basic.outfit_name mustEqual ""
|
||||
basic.outfit_logo mustEqual 0
|
||||
basic.backpack mustEqual false
|
||||
basic.facingPitch mustEqual 2.8125f
|
||||
basic.facingYawUpper mustEqual 210.9375f
|
||||
basic.lfs mustEqual true
|
||||
basic.grenade_state mustEqual GrenadeState.None
|
||||
basic.is_cloaking mustEqual false
|
||||
basic.charging_pose mustEqual false
|
||||
basic.on_zipline mustEqual false
|
||||
basic.ribbons.upper mustEqual MeritCommendation.None
|
||||
basic.ribbons.middle mustEqual MeritCommendation.None
|
||||
basic.ribbons.lower mustEqual MeritCommendation.None
|
||||
basic.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
|
||||
char.unk1 mustEqual 1
|
||||
char.unk2 mustEqual 7
|
||||
char.unk3 mustEqual 7
|
||||
char.staminaMax mustEqual 100
|
||||
char.stamina mustEqual 100
|
||||
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"
|
||||
char.firstTimeEvents(2) mustEqual "used_beamer"
|
||||
char.firstTimeEvents(3) mustEqual "map13"
|
||||
char.tutorials.size mustEqual 0
|
||||
char.cosmetics.isDefined mustEqual false
|
||||
inv.isDefined mustEqual true
|
||||
val inventory = inv.get.contents
|
||||
inventory.size mustEqual 10
|
||||
//0
|
||||
inventory.head.objectClass mustEqual ObjectClass.beamer
|
||||
inventory.head.guid mustEqual PlanetSideGUID(76)
|
||||
inventory.head.parentSlot mustEqual 0
|
||||
var wep = inventory.head.obj.asInstanceOf[DetailedWeaponData]
|
||||
wep.ammo.head.objectClass mustEqual ObjectClass.energy_cell
|
||||
wep.ammo.head.guid mustEqual PlanetSideGUID(77)
|
||||
wep.ammo.head.parentSlot mustEqual 0
|
||||
wep.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 16
|
||||
//1
|
||||
inventory(1).objectClass mustEqual ObjectClass.suppressor
|
||||
inventory(1).guid mustEqual PlanetSideGUID(78)
|
||||
inventory(1).parentSlot mustEqual 2
|
||||
wep = inventory(1).obj.asInstanceOf[DetailedWeaponData]
|
||||
wep.ammo.head.objectClass mustEqual ObjectClass.bullet_9mm
|
||||
wep.ammo.head.guid mustEqual PlanetSideGUID(79)
|
||||
wep.ammo.head.parentSlot mustEqual 0
|
||||
wep.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 25
|
||||
//2
|
||||
inventory(2).objectClass mustEqual ObjectClass.forceblade
|
||||
inventory(2).guid mustEqual PlanetSideGUID(80)
|
||||
inventory(2).parentSlot mustEqual 4
|
||||
wep = inventory(2).obj.asInstanceOf[DetailedWeaponData]
|
||||
wep.ammo.head.objectClass mustEqual ObjectClass.melee_ammo
|
||||
wep.ammo.head.guid mustEqual PlanetSideGUID(81)
|
||||
wep.ammo.head.parentSlot mustEqual 0
|
||||
wep.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 1
|
||||
//3
|
||||
inventory(3).objectClass mustEqual ObjectClass.locker_container
|
||||
inventory(3).guid mustEqual PlanetSideGUID(82)
|
||||
inventory(3).parentSlot mustEqual 5
|
||||
inventory(3).obj.isInstanceOf[DetailedLockerContainerData] mustEqual true
|
||||
inventory(3).obj.asInstanceOf[DetailedLockerContainerData].inventory.isDefined mustEqual false
|
||||
//4
|
||||
inventory(4).objectClass mustEqual ObjectClass.bullet_9mm
|
||||
inventory(4).guid mustEqual PlanetSideGUID(83)
|
||||
inventory(4).parentSlot mustEqual 6
|
||||
inventory(4).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
|
||||
//5
|
||||
inventory(5).objectClass mustEqual ObjectClass.bullet_9mm
|
||||
inventory(5).guid mustEqual PlanetSideGUID(84)
|
||||
inventory(5).parentSlot mustEqual 9
|
||||
inventory(5).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
|
||||
//6
|
||||
inventory(6).objectClass mustEqual ObjectClass.bullet_9mm
|
||||
inventory(6).guid mustEqual PlanetSideGUID(85)
|
||||
inventory(6).parentSlot mustEqual 12
|
||||
inventory(6).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
|
||||
//7
|
||||
inventory(7).objectClass mustEqual ObjectClass.bullet_9mm_AP
|
||||
inventory(7).guid mustEqual PlanetSideGUID(86)
|
||||
inventory(7).parentSlot mustEqual 33
|
||||
inventory(7).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
|
||||
//8
|
||||
inventory(8).objectClass mustEqual ObjectClass.energy_cell
|
||||
inventory(8).guid mustEqual PlanetSideGUID(87)
|
||||
inventory(8).parentSlot mustEqual 36
|
||||
inventory(8).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
|
||||
//9
|
||||
inventory(9).objectClass mustEqual ObjectClass.remote_electronics_kit
|
||||
inventory(9).guid mustEqual PlanetSideGUID(88)
|
||||
inventory(9).parentSlot mustEqual 39
|
||||
//the rek has data but none worth testing here
|
||||
hand mustEqual DrawnSlot.Pistol1
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
|
|
@ -155,76 +157,80 @@ class DetailedCharacterDataTest extends Specification {
|
|||
//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.isDefined mustEqual true
|
||||
val char = data.get.asInstanceOf[DetailedCharacterData]
|
||||
DetailedCharacterData.isBR24(char.bep) mustEqual true
|
||||
char.certs.size mustEqual 15
|
||||
char.certs.head mustEqual CertificationType.StandardAssault
|
||||
char.certs(14) mustEqual CertificationType.CombatEngineering
|
||||
char.implants.size mustEqual 3
|
||||
char.implants.head.implant mustEqual ImplantType.AudioAmplifier
|
||||
char.implants.head.activation mustEqual None
|
||||
char.implants(1).implant mustEqual ImplantType.Targeting
|
||||
char.implants(1).activation mustEqual None
|
||||
char.implants(2).implant mustEqual ImplantType.Surge
|
||||
char.implants(2).activation mustEqual None
|
||||
char.firstTimeEvents.size mustEqual 298
|
||||
char.firstTimeEvents.head mustEqual "xpe_overhead_map"
|
||||
char.firstTimeEvents(297) mustEqual "map10"
|
||||
char.tutorials.size mustEqual 3
|
||||
char.tutorials.head mustEqual "training_start_nc"
|
||||
char.tutorials(1) mustEqual "training_ui"
|
||||
char.tutorials(2) mustEqual "training_map"
|
||||
char.cosmetics.isDefined mustEqual true
|
||||
char.cosmetics.get.no_helmet mustEqual true
|
||||
char.cosmetics.get.beret mustEqual true
|
||||
char.cosmetics.get.earpiece mustEqual true
|
||||
char.cosmetics.get.sunglasses mustEqual true
|
||||
char.cosmetics.get.brimmed_cap mustEqual false
|
||||
//inventory
|
||||
char.inventory.isDefined mustEqual true
|
||||
char.inventory.get.contents.size mustEqual 12
|
||||
//0
|
||||
char.inventory.get.contents.head.objectClass mustEqual 531
|
||||
char.inventory.get.contents.head.guid mustEqual PlanetSideGUID(4202)
|
||||
char.inventory.get.contents.head.parentSlot mustEqual 0
|
||||
val wep1 = char.inventory.get.contents.head.obj.asInstanceOf[DetailedWeaponData]
|
||||
wep1.unk1 mustEqual 2
|
||||
wep1.unk2 mustEqual 8
|
||||
wep1.ammo.head.objectClass mustEqual 389
|
||||
wep1.ammo.head.guid mustEqual PlanetSideGUID(3942)
|
||||
wep1.ammo.head.parentSlot mustEqual 0
|
||||
wep1.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].unk mustEqual 8
|
||||
wep1.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 100
|
||||
//4
|
||||
char.inventory.get.contents(4).objectClass mustEqual 456
|
||||
char.inventory.get.contents(4).guid mustEqual PlanetSideGUID(5374)
|
||||
char.inventory.get.contents(4).parentSlot mustEqual 5
|
||||
char.inventory.get.contents(4).obj.asInstanceOf[DetailedLockerContainerData].inventory.get.contents.size mustEqual 61
|
||||
//11
|
||||
char.inventory.get.contents(11).objectClass mustEqual 673
|
||||
char.inventory.get.contents(11).guid mustEqual PlanetSideGUID(3661)
|
||||
char.inventory.get.contents(11).parentSlot mustEqual 60
|
||||
val wep2 = char.inventory.get.contents(11).obj.asInstanceOf[DetailedWeaponData]
|
||||
wep2.unk1 mustEqual 2
|
||||
wep2.unk2 mustEqual 8
|
||||
wep2.ammo.head.objectClass mustEqual 674
|
||||
wep2.ammo.head.guid mustEqual PlanetSideGUID(8542)
|
||||
wep2.ammo.head.parentSlot mustEqual 0
|
||||
wep2.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].unk mustEqual 8
|
||||
wep2.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 3
|
||||
char.drawn_slot mustEqual DrawnSlot.None
|
||||
data match {
|
||||
case Some(DetailedPlayerData(Some(_), _, char, inv, hand)) =>
|
||||
DetailedCharacterData.isBR24(char.bep) mustEqual true
|
||||
char.certs.size mustEqual 15
|
||||
char.certs.head mustEqual CertificationType.StandardAssault
|
||||
char.certs(14) mustEqual CertificationType.CombatEngineering
|
||||
char.implants.size mustEqual 3
|
||||
char.implants.head.implant mustEqual ImplantType.AudioAmplifier
|
||||
char.implants.head.activation mustEqual None
|
||||
char.implants(1).implant mustEqual ImplantType.Targeting
|
||||
char.implants(1).activation mustEqual None
|
||||
char.implants(2).implant mustEqual ImplantType.Surge
|
||||
char.implants(2).activation mustEqual None
|
||||
char.firstTimeEvents.size mustEqual 298
|
||||
char.firstTimeEvents.head mustEqual "xpe_overhead_map"
|
||||
char.firstTimeEvents(297) mustEqual "map10"
|
||||
char.tutorials.size mustEqual 3
|
||||
char.tutorials.head mustEqual "training_start_nc"
|
||||
char.tutorials(1) mustEqual "training_ui"
|
||||
char.tutorials(2) mustEqual "training_map"
|
||||
char.cosmetics.isDefined mustEqual true
|
||||
char.cosmetics.get.no_helmet mustEqual true
|
||||
char.cosmetics.get.beret mustEqual true
|
||||
char.cosmetics.get.earpiece mustEqual true
|
||||
char.cosmetics.get.sunglasses mustEqual true
|
||||
char.cosmetics.get.brimmed_cap mustEqual false
|
||||
//inventory
|
||||
inv.isDefined mustEqual true
|
||||
inv.get.contents.size mustEqual 12
|
||||
//0
|
||||
inv.get.contents.head.objectClass mustEqual 531
|
||||
inv.get.contents.head.guid mustEqual PlanetSideGUID(4202)
|
||||
inv.get.contents.head.parentSlot mustEqual 0
|
||||
val wep1 = inv.get.contents.head.obj.asInstanceOf[DetailedWeaponData]
|
||||
wep1.unk1 mustEqual 2
|
||||
wep1.unk2 mustEqual 8
|
||||
wep1.ammo.head.objectClass mustEqual 389
|
||||
wep1.ammo.head.guid mustEqual PlanetSideGUID(3942)
|
||||
wep1.ammo.head.parentSlot mustEqual 0
|
||||
wep1.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].unk mustEqual 8
|
||||
wep1.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 100
|
||||
//4
|
||||
inv.get.contents(4).objectClass mustEqual 456
|
||||
inv.get.contents(4).guid mustEqual PlanetSideGUID(5374)
|
||||
inv.get.contents(4).parentSlot mustEqual 5
|
||||
inv.get.contents(4).obj.asInstanceOf[DetailedLockerContainerData].inventory.get.contents.size mustEqual 61
|
||||
//11
|
||||
inv.get.contents(11).objectClass mustEqual 673
|
||||
inv.get.contents(11).guid mustEqual PlanetSideGUID(3661)
|
||||
inv.get.contents(11).parentSlot mustEqual 60
|
||||
val wep2 = inv.get.contents(11).obj.asInstanceOf[DetailedWeaponData]
|
||||
wep2.unk1 mustEqual 2
|
||||
wep2.unk2 mustEqual 8
|
||||
wep2.ammo.head.objectClass mustEqual 674
|
||||
wep2.ammo.head.guid mustEqual PlanetSideGUID(8542)
|
||||
wep2.ammo.head.parentSlot mustEqual 0
|
||||
wep2.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].unk mustEqual 8
|
||||
wep2.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 3
|
||||
|
||||
hand mustEqual DrawnSlot.None
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"encode (character)" in {
|
||||
val app = CharacterAppearanceData(
|
||||
PlacementData(
|
||||
Vector3(3674.8438f, 2726.789f, 91.15625f),
|
||||
Vector3(0f, 0f, 36.5625f)
|
||||
),
|
||||
val pos : PlacementData = PlacementData(
|
||||
3674.8438f, 2726.789f, 91.15625f,
|
||||
0, 0, 36.5625f
|
||||
)
|
||||
val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData(
|
||||
BasicCharacterData(
|
||||
"IlllIIIlllIlIllIlllIllI",
|
||||
PlanetSideEmpire.VS,
|
||||
|
|
@ -247,19 +253,7 @@ class DetailedCharacterDataTest extends Specification {
|
|||
false,
|
||||
RibbonBars()
|
||||
)
|
||||
val inv = InventoryItemData(ObjectClass.beamer, PlanetSideGUID(76), 0, DetailedWeaponData(4, 8, ObjectClass.energy_cell, PlanetSideGUID(77), 0, DetailedAmmoBoxData(8, 16))) ::
|
||||
InventoryItemData(ObjectClass.suppressor, PlanetSideGUID(78), 2, DetailedWeaponData(4, 8, ObjectClass.bullet_9mm, PlanetSideGUID(79), 0, DetailedAmmoBoxData(8, 25))) ::
|
||||
InventoryItemData(ObjectClass.forceblade, PlanetSideGUID(80), 4, DetailedWeaponData(4, 8, ObjectClass.melee_ammo, PlanetSideGUID(81), 0, DetailedAmmoBoxData(8, 1))) ::
|
||||
InventoryItemData(ObjectClass.locker_container, PlanetSideGUID(82), 5, DetailedLockerContainerData(8)) ::
|
||||
InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(83), 6, DetailedAmmoBoxData(8, 50)) ::
|
||||
InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(84), 9, DetailedAmmoBoxData(8, 50)) ::
|
||||
InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(85), 12, DetailedAmmoBoxData(8, 50)) ::
|
||||
InventoryItemData(ObjectClass.bullet_9mm_AP, PlanetSideGUID(86), 33, DetailedAmmoBoxData(8, 50)) ::
|
||||
InventoryItemData(ObjectClass.energy_cell, PlanetSideGUID(87), 36, DetailedAmmoBoxData(8, 50)) ::
|
||||
InventoryItemData(ObjectClass.remote_electronics_kit, PlanetSideGUID(88), 39, DetailedREKData(8)) ::
|
||||
Nil
|
||||
val obj = DetailedCharacterData(
|
||||
app,
|
||||
val char : (Option[Int])=>DetailedCharacterData = DetailedCharacterData(
|
||||
0,
|
||||
0,
|
||||
100, 100,
|
||||
|
|
@ -278,13 +272,25 @@ class DetailedCharacterDataTest extends Specification {
|
|||
List(),
|
||||
"xpe_sanctuary_help" :: "xpe_th_firemodes" :: "used_beamer" :: "map13" :: Nil,
|
||||
List.empty,
|
||||
None,
|
||||
Some(InventoryData(inv)),
|
||||
DrawnSlot.Pistol1
|
||||
None
|
||||
)
|
||||
val inv = InventoryData(
|
||||
InventoryItemData(ObjectClass.beamer, PlanetSideGUID(76), 0, DetailedWeaponData(4, 8, ObjectClass.energy_cell, PlanetSideGUID(77), 0, DetailedAmmoBoxData(8, 16))) ::
|
||||
InventoryItemData(ObjectClass.suppressor, PlanetSideGUID(78), 2, DetailedWeaponData(4, 8, ObjectClass.bullet_9mm, PlanetSideGUID(79), 0, DetailedAmmoBoxData(8, 25))) ::
|
||||
InventoryItemData(ObjectClass.forceblade, PlanetSideGUID(80), 4, DetailedWeaponData(4, 8, ObjectClass.melee_ammo, PlanetSideGUID(81), 0, DetailedAmmoBoxData(8, 1))) ::
|
||||
InventoryItemData(ObjectClass.locker_container, PlanetSideGUID(82), 5, DetailedLockerContainerData(8)) ::
|
||||
InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(83), 6, DetailedAmmoBoxData(8, 50)) ::
|
||||
InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(84), 9, DetailedAmmoBoxData(8, 50)) ::
|
||||
InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(85), 12, DetailedAmmoBoxData(8, 50)) ::
|
||||
InventoryItemData(ObjectClass.bullet_9mm_AP, PlanetSideGUID(86), 33, DetailedAmmoBoxData(8, 50)) ::
|
||||
InventoryItemData(ObjectClass.energy_cell, PlanetSideGUID(87), 36, DetailedAmmoBoxData(8, 50)) ::
|
||||
InventoryItemData(ObjectClass.remote_electronics_kit, PlanetSideGUID(88), 39, DetailedREKData(8)) ::
|
||||
Nil
|
||||
)
|
||||
val obj = DetailedPlayerData.apply(pos, app, char, inv, DrawnSlot.Pistol1)
|
||||
|
||||
val msg = ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
val pkt_bitv = pkt.toBitVector
|
||||
val ori_bitv = string_testchar.toBitVector
|
||||
pkt_bitv.take(153) mustEqual ori_bitv.take(153) //skip 1
|
||||
|
|
@ -295,26 +301,31 @@ class DetailedCharacterDataTest extends Specification {
|
|||
}
|
||||
|
||||
"encode (character, br32)" in {
|
||||
val obj = DetailedCharacterData(
|
||||
CharacterAppearanceData(
|
||||
PlacementData(
|
||||
Vector3(5500.0f, 3800.0f, 71.484375f),
|
||||
Vector3(0.0f, 0.0f, 90.0f),
|
||||
None
|
||||
),
|
||||
BasicCharacterData("KiCkJr", PlanetSideEmpire.NC, CharacterGender.Male, 24, 4),
|
||||
3,
|
||||
false, false,
|
||||
ExoSuitType.Agile,
|
||||
"",
|
||||
14,
|
||||
false,
|
||||
354.375f, 354.375f,
|
||||
false,
|
||||
GrenadeState.None,
|
||||
false, false, false,
|
||||
RibbonBars(MeritCommendation.Loser4, MeritCommendation.EventNCElite, MeritCommendation.HeavyAssault6, MeritCommendation.SixYearNC)
|
||||
),
|
||||
val pos : PlacementData = PlacementData(
|
||||
Vector3(5500.0f, 3800.0f, 71.484375f),
|
||||
Vector3(0, 0, 90.0f),
|
||||
None
|
||||
)
|
||||
val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData(
|
||||
BasicCharacterData("KiCkJr", PlanetSideEmpire.NC, CharacterGender.Male, 24, 4),
|
||||
3,
|
||||
false, false,
|
||||
ExoSuitType.Agile,
|
||||
"",
|
||||
14,
|
||||
false,
|
||||
354.375f, 354.375f,
|
||||
false,
|
||||
GrenadeState.None,
|
||||
false, false, false,
|
||||
RibbonBars(
|
||||
MeritCommendation.Loser4,
|
||||
MeritCommendation.EventNCElite,
|
||||
MeritCommendation.HeavyAssault6,
|
||||
MeritCommendation.SixYearNC
|
||||
)
|
||||
)
|
||||
val char : (Option[Int])=>DetailedCharacterData = DetailedCharacterData(
|
||||
6366766,
|
||||
694787,
|
||||
100, 100, 100,
|
||||
|
|
@ -647,198 +658,196 @@ class DetailedCharacterDataTest extends Specification {
|
|||
"training_ui",
|
||||
"training_map"
|
||||
),
|
||||
Some(Cosmetics(true, true, true, true, false)),
|
||||
Some(
|
||||
InventoryData(
|
||||
List(
|
||||
InternalSlot(531, PlanetSideGUID(4202), 0,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(389, PlanetSideGUID(3942), 0,DetailedAmmoBoxData(8, 100))))
|
||||
),
|
||||
InternalSlot(132, PlanetSideGUID(6924), 1,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(111, PlanetSideGUID(9157), 0, DetailedAmmoBoxData(8, 100))))
|
||||
),
|
||||
InternalSlot(714, PlanetSideGUID(8498), 2,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(755, PlanetSideGUID(5356), 0, DetailedAmmoBoxData(8, 16))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(7198), 4,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(540, PlanetSideGUID(5009), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(456, PlanetSideGUID(5374), 5,
|
||||
DetailedLockerContainerData(8, Some(InventoryData(List(
|
||||
InternalSlot(429, PlanetSideGUID(3021), 0,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(272, PlanetSideGUID(8729), 0, DetailedAmmoBoxData(8, 0))))
|
||||
),
|
||||
InternalSlot(838, PlanetSideGUID(8467), 9,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(839, PlanetSideGUID(8603), 0, DetailedAmmoBoxData(8, 5))))
|
||||
),
|
||||
InternalSlot(272, PlanetSideGUID(3266), 18, DetailedAmmoBoxData(8, 27)),
|
||||
InternalSlot(577, PlanetSideGUID(2934), 22,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(111, PlanetSideGUID(4682), 0, DetailedAmmoBoxData(8, 100))))
|
||||
),
|
||||
InternalSlot(839, PlanetSideGUID(3271), 90, DetailedAmmoBoxData(8, 15)),
|
||||
InternalSlot(839, PlanetSideGUID(7174), 94, DetailedAmmoBoxData(8, 6)),
|
||||
InternalSlot(429, PlanetSideGUID(6084), 98,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(272, PlanetSideGUID(5928), 0, DetailedAmmoBoxData(8, 35))))
|
||||
),
|
||||
InternalSlot(462, PlanetSideGUID(5000), 108,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(6277), 0, DetailedAmmoBoxData(8, 150))))
|
||||
),
|
||||
InternalSlot(429, PlanetSideGUID(4341), 189,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(272, PlanetSideGUID(7043), 0, DetailedAmmoBoxData(8, 35))))
|
||||
),
|
||||
InternalSlot(556, PlanetSideGUID(4168), 198,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(28, PlanetSideGUID(8937), 0, DetailedAmmoBoxData(8, 100))))
|
||||
),
|
||||
InternalSlot(272, PlanetSideGUID(3173), 207, DetailedAmmoBoxData(8, 50)),
|
||||
InternalSlot(462, PlanetSideGUID(3221), 210,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(4031), 0, DetailedAmmoBoxData(8, 150))))
|
||||
),
|
||||
InternalSlot(556, PlanetSideGUID(6853), 280,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(29, PlanetSideGUID(8524), 0, DetailedAmmoBoxData(8, 67))))
|
||||
),
|
||||
InternalSlot(556, PlanetSideGUID(4569), 290,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(28, PlanetSideGUID(5584), 0, DetailedAmmoBoxData(8, 100))))
|
||||
),
|
||||
InternalSlot(462, PlanetSideGUID(9294), 300,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(3118), 0, DetailedAmmoBoxData(8, 150))))
|
||||
),
|
||||
InternalSlot(272, PlanetSideGUID(4759), 387, DetailedAmmoBoxData(8, 50)),
|
||||
InternalSlot(462, PlanetSideGUID(7377), 390,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(8155), 0, DetailedAmmoBoxData(8, 150))))
|
||||
),
|
||||
InternalSlot(843, PlanetSideGUID(6709), 480, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(843, PlanetSideGUID(5276), 484, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(843, PlanetSideGUID(7769), 488, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(844, PlanetSideGUID(5334), 492, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(844, PlanetSideGUID(6219), 496, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(842, PlanetSideGUID(7279), 500, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(842, PlanetSideGUID(5415), 504, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(175, PlanetSideGUID(5741), 540,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5183), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(6208), 541,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5029), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(8589), 542,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(9217), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(8901), 543,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7633), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(8419), 544,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6546), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(4715), 545,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(8453), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(3577), 546,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(9202), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(6003), 547,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(3260), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(9140), 548,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(3815),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(4913), 549,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(7222),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(6954), 550,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(2953),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(6405), 551,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(4676),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(8915), 552,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(4018),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(4993), 553,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(6775),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(5053), 554,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(6418),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(9244), 555,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(3327),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(6292), 556,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(6918),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(842, PlanetSideGUID(5357), 558, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(844, PlanetSideGUID(4435), 562, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(843, PlanetSideGUID(7242), 566, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(175, PlanetSideGUID(7330), 570,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4786), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(7415), 571,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6536), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(3949), 572,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7526), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(3805), 573,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7358), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(4493), 574,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6852), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(5762), 575,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(3463), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(3315), 576,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7619), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(6263), 577,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5912), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(4028), 578,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(8021), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(2843), 579,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7250), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(9143), 580,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5195), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(5024), 581,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4287), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(6582), 582,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4915), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(6425), 583,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(8872), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(4431), 584,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4191), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(8339), 585,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7317), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(3277), 586,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6469), 0, DetailedAmmoBoxData(8, 1))))
|
||||
)
|
||||
))))
|
||||
),
|
||||
InternalSlot(213, PlanetSideGUID(6877), 6, DetailedCommandDetonaterData(4, 8)),
|
||||
InternalSlot(755, PlanetSideGUID(6227), 9, DetailedAmmoBoxData(8, 16)),
|
||||
InternalSlot(728, PlanetSideGUID(7181), 12, DetailedREKData(4, 16)),
|
||||
InternalSlot(536, PlanetSideGUID(4077), 33, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(680, PlanetSideGUID(4377), 37,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(681, PlanetSideGUID(8905), 0, DetailedAmmoBoxData(8, 3))))
|
||||
),
|
||||
InternalSlot(32, PlanetSideGUID(5523), 39, DetailedACEData(4)),
|
||||
InternalSlot(673, PlanetSideGUID(3661), 60,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(674, PlanetSideGUID(8542), 0, DetailedAmmoBoxData(8, 3))))
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
DrawnSlot.None
|
||||
Some(Cosmetics(true, true, true, true, false))
|
||||
)
|
||||
val inv = InventoryData(
|
||||
List(
|
||||
InternalSlot(531, PlanetSideGUID(4202), 0,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(389, PlanetSideGUID(3942), 0,DetailedAmmoBoxData(8, 100))))
|
||||
),
|
||||
InternalSlot(132, PlanetSideGUID(6924), 1,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(111, PlanetSideGUID(9157), 0, DetailedAmmoBoxData(8, 100))))
|
||||
),
|
||||
InternalSlot(714, PlanetSideGUID(8498), 2,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(755, PlanetSideGUID(5356), 0, DetailedAmmoBoxData(8, 16))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(7198), 4,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(540, PlanetSideGUID(5009), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(456, PlanetSideGUID(5374), 5,
|
||||
DetailedLockerContainerData(8, Some(InventoryData(List(
|
||||
InternalSlot(429, PlanetSideGUID(3021), 0,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(272, PlanetSideGUID(8729), 0, DetailedAmmoBoxData(8, 0))))
|
||||
),
|
||||
InternalSlot(838, PlanetSideGUID(8467), 9,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(839, PlanetSideGUID(8603), 0, DetailedAmmoBoxData(8, 5))))
|
||||
),
|
||||
InternalSlot(272, PlanetSideGUID(3266), 18, DetailedAmmoBoxData(8, 27)),
|
||||
InternalSlot(577, PlanetSideGUID(2934), 22,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(111, PlanetSideGUID(4682), 0, DetailedAmmoBoxData(8, 100))))
|
||||
),
|
||||
InternalSlot(839, PlanetSideGUID(3271), 90, DetailedAmmoBoxData(8, 15)),
|
||||
InternalSlot(839, PlanetSideGUID(7174), 94, DetailedAmmoBoxData(8, 6)),
|
||||
InternalSlot(429, PlanetSideGUID(6084), 98,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(272, PlanetSideGUID(5928), 0, DetailedAmmoBoxData(8, 35))))
|
||||
),
|
||||
InternalSlot(462, PlanetSideGUID(5000), 108,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(6277), 0, DetailedAmmoBoxData(8, 150))))
|
||||
),
|
||||
InternalSlot(429, PlanetSideGUID(4341), 189,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(272, PlanetSideGUID(7043), 0, DetailedAmmoBoxData(8, 35))))
|
||||
),
|
||||
InternalSlot(556, PlanetSideGUID(4168), 198,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(28, PlanetSideGUID(8937), 0, DetailedAmmoBoxData(8, 100))))
|
||||
),
|
||||
InternalSlot(272, PlanetSideGUID(3173), 207, DetailedAmmoBoxData(8, 50)),
|
||||
InternalSlot(462, PlanetSideGUID(3221), 210,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(4031), 0, DetailedAmmoBoxData(8, 150))))
|
||||
),
|
||||
InternalSlot(556, PlanetSideGUID(6853), 280,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(29, PlanetSideGUID(8524), 0, DetailedAmmoBoxData(8, 67))))
|
||||
),
|
||||
InternalSlot(556, PlanetSideGUID(4569), 290,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(28, PlanetSideGUID(5584), 0, DetailedAmmoBoxData(8, 100))))
|
||||
),
|
||||
InternalSlot(462, PlanetSideGUID(9294), 300,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(3118), 0, DetailedAmmoBoxData(8, 150))))
|
||||
),
|
||||
InternalSlot(272, PlanetSideGUID(4759), 387, DetailedAmmoBoxData(8, 50)),
|
||||
InternalSlot(462, PlanetSideGUID(7377), 390,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(8155), 0, DetailedAmmoBoxData(8, 150))))
|
||||
),
|
||||
InternalSlot(843, PlanetSideGUID(6709), 480, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(843, PlanetSideGUID(5276), 484, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(843, PlanetSideGUID(7769), 488, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(844, PlanetSideGUID(5334), 492, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(844, PlanetSideGUID(6219), 496, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(842, PlanetSideGUID(7279), 500, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(842, PlanetSideGUID(5415), 504, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(175, PlanetSideGUID(5741), 540,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5183), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(6208), 541,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5029), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(8589), 542,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(9217), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(8901), 543,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7633), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(8419), 544,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6546), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(4715), 545,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(8453), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(3577), 546,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(9202), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(6003), 547,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(3260), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(9140), 548,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(3815),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(4913), 549,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(7222),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(6954), 550,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(2953),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(6405), 551,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(4676),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(8915), 552,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(4018),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(4993), 553,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(6775),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(5053), 554,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(6418),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(9244), 555,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(3327),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(6292), 556,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(6918),0,DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(842, PlanetSideGUID(5357), 558, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(844, PlanetSideGUID(4435), 562, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(843, PlanetSideGUID(7242), 566, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(175, PlanetSideGUID(7330), 570,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4786), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(7415), 571,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6536), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(3949), 572,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7526), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(3805), 573,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7358), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(4493), 574,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6852), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(5762), 575,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(3463), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(3315), 576,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7619), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(324, PlanetSideGUID(6263), 577,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5912), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(4028), 578,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(8021), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(2843), 579,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7250), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(9143), 580,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5195), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(5024), 581,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4287), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(6582), 582,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4915), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(6425), 583,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(8872), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(468, PlanetSideGUID(4431), 584,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4191), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(8339), 585,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7317), 0, DetailedAmmoBoxData(8, 1))))
|
||||
),
|
||||
InternalSlot(175, PlanetSideGUID(3277), 586,
|
||||
DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6469), 0, DetailedAmmoBoxData(8, 1))))
|
||||
)
|
||||
))))
|
||||
),
|
||||
InternalSlot(213, PlanetSideGUID(6877), 6, DetailedCommandDetonaterData(4, 8)),
|
||||
InternalSlot(755, PlanetSideGUID(6227), 9, DetailedAmmoBoxData(8, 16)),
|
||||
InternalSlot(728, PlanetSideGUID(7181), 12, DetailedREKData(4, 16)),
|
||||
InternalSlot(536, PlanetSideGUID(4077), 33, DetailedAmmoBoxData(8, 1)),
|
||||
InternalSlot(680, PlanetSideGUID(4377), 37,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(681, PlanetSideGUID(8905), 0, DetailedAmmoBoxData(8, 3))))
|
||||
),
|
||||
InternalSlot(32, PlanetSideGUID(5523), 39, DetailedACEData(4)),
|
||||
InternalSlot(673, PlanetSideGUID(3661), 60,
|
||||
DetailedWeaponData(2, 8, 0, List(InternalSlot(674, PlanetSideGUID(8542), 0, DetailedAmmoBoxData(8, 3))))
|
||||
)
|
||||
)
|
||||
)
|
||||
val obj = DetailedPlayerData(pos, app, char, inv, DrawnSlot.None)
|
||||
|
||||
val msg = ObjectCreateDetailedMessage(ObjectClass.avatar, PlanetSideGUID(75), obj)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
val pkt_bitv = pkt.toBitVector
|
||||
val ori_bitv = string_testchar_br32.toBitVector
|
||||
pkt_bitv.take(153) mustEqual ori_bitv.take(153) //skip 1
|
||||
|
|
|
|||
|
|
@ -1828,7 +1828,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
galaxy ! Zone.Lattice.RequestSpawnPoint(u5.toInt, player, u2.toInt)
|
||||
|
||||
case msg @ SetChatFilterMessage(send_channel, origin, whitelist) =>
|
||||
log.info("SetChatFilters: " + msg)
|
||||
//log.info("SetChatFilters: " + msg)
|
||||
|
||||
case msg @ ChatMsg(messagetype, has_wide_contents, recipient, contents, note_contents) =>
|
||||
var makeReply : Boolean = true
|
||||
|
|
|
|||
|
|
@ -452,45 +452,44 @@ class PacketCodingActorHTest extends ActorTest {
|
|||
}
|
||||
|
||||
class PacketCodingActorITest extends ActorTest {
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
val pos : PlacementData = PlacementData(Vector3.Zero, Vector3.Zero)
|
||||
val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData(
|
||||
BasicCharacterData("IlllIIIlllIlIllIlllIllI", PlanetSideEmpire.VS, CharacterGender.Female, 41, 1),
|
||||
3,
|
||||
false,
|
||||
false,
|
||||
ExoSuitType.Standard,
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
2.8125f, 210.9375f,
|
||||
true,
|
||||
GrenadeState.None,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
RibbonBars()
|
||||
)
|
||||
var char : (Option[Int])=>DetailedCharacterData = DetailedCharacterData(
|
||||
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(),
|
||||
List.empty,
|
||||
None
|
||||
)
|
||||
val obj = DetailedPlayerData(pos, app, char, InventoryData(Nil), DrawnSlot.None)
|
||||
val pkt = MultiPacketBundle(List(ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj)))
|
||||
val string_hex = hex"000900001879060000bc84b000000000000000000002040000097049006c006c006c004900490049006c006c006c0049006c0049006c006c0049006c006c006c0049006c006c0049008452700000000000000000000000000000002000000fe6a703fffffffffffffffffffffffffffffffc00000000000000000000000000000000000000019001900064000001007ec800c80000000000000000000000000000000000000001c00042c54686c7000000000000000000000000000000000000000000000000000000000000000000000000200700"
|
||||
|
||||
"PacketCodingActor" should {
|
||||
"bundle an r-originating packet into an l-facing SlottedMetaPacket byte stream data (SlottedMetaPacket)" in {
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
val obj = DetailedCharacterData(
|
||||
CharacterAppearanceData(
|
||||
PlacementData(Vector3.Zero, Vector3.Zero),
|
||||
BasicCharacterData("IlllIIIlllIlIllIlllIllI", PlanetSideEmpire.VS, CharacterGender.Female, 41, 1),
|
||||
3,
|
||||
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(),
|
||||
List.empty,
|
||||
None,
|
||||
Some(InventoryData(Nil)),
|
||||
DrawnSlot.None
|
||||
)
|
||||
val pkt = MultiPacketBundle(List(ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj)))
|
||||
val string_hex = hex"000900001879060000bc84b000000000000000000002040000097049006c006c006c004900490049006c006c006c0049006c0049006c006c0049006c006c006c0049006c006c0049008452700000000000000000000000000000002000000fe6a703fffffffffffffffffffffffffffffffc00000000000000000000000000000000000000019001900064000001007ec800c80000000000000000000000000000000000000001c00042c54686c7000000000000000000000000000000000000000000000000000000000000000000000000200700"
|
||||
|
||||
val probe1 = TestProbe()
|
||||
val probe2 = system.actorOf(Props(classOf[ActorTest.MDCTestProbe], probe1), "mdc-probe")
|
||||
val pca : ActorRef = system.actorOf(Props[PacketCodingActor], "pca")
|
||||
|
|
@ -547,25 +546,25 @@ class PacketCodingActorJTest extends ActorTest {
|
|||
|
||||
class PacketCodingActorKTest extends ActorTest {
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
val obj = DetailedCharacterData(
|
||||
CharacterAppearanceData(
|
||||
PlacementData(Vector3.Zero, Vector3.Zero),
|
||||
BasicCharacterData("IlllIIIlllIlIllIlllIllI", PlanetSideEmpire.VS, CharacterGender.Female, 41, 1),
|
||||
3,
|
||||
false,
|
||||
false,
|
||||
ExoSuitType.Standard,
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
2.8125f, 210.9375f,
|
||||
true,
|
||||
GrenadeState.None,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
RibbonBars()
|
||||
),
|
||||
val pos : PlacementData = PlacementData(Vector3.Zero, Vector3.Zero)
|
||||
val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData(
|
||||
BasicCharacterData("IlllIIIlllIlIllIlllIllI", PlanetSideEmpire.VS, CharacterGender.Female, 41, 1),
|
||||
3,
|
||||
false,
|
||||
false,
|
||||
ExoSuitType.Standard,
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
2.8125f, 210.9375f,
|
||||
true,
|
||||
GrenadeState.None,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
RibbonBars()
|
||||
)
|
||||
var char : (Option[Int])=>DetailedCharacterData = DetailedCharacterData(
|
||||
0,
|
||||
0,
|
||||
100, 100,
|
||||
|
|
@ -576,10 +575,9 @@ class PacketCodingActorKTest extends ActorTest {
|
|||
List(),
|
||||
List("xpe_sanctuary_help", "xpe_th_firemodes", "used_beamer", "map13"),
|
||||
List.empty,
|
||||
None,
|
||||
Some(InventoryData(Nil)),
|
||||
DrawnSlot.None
|
||||
None
|
||||
)
|
||||
val obj = DetailedPlayerData(pos, app, char, InventoryData(Nil), DrawnSlot.None)
|
||||
val list = List(
|
||||
ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj),
|
||||
ObjectDeleteMessage(PlanetSideGUID(1103), 2),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue