mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-14 07:55:07 +00:00
adding comments to OC*M Codec files; modifying converters to take advantage of the new packet field extensions; fixing two pieces of GUID code that relied on throwing Exceptions to function correctly
This commit is contained in:
parent
3ac0010052
commit
19f77fc9b5
11 changed files with 1242 additions and 318 deletions
|
|
@ -64,36 +64,59 @@ object AvatarConverter {
|
||||||
* @return the resulting `CharacterAppearanceData`
|
* @return the resulting `CharacterAppearanceData`
|
||||||
*/
|
*/
|
||||||
def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
||||||
CharacterAppearanceData(
|
val alt_model_flag : Boolean = obj.isBackpack
|
||||||
|
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
||||||
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, obj.Voice),
|
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, obj.Voice),
|
||||||
black_ops = false,
|
black_ops = false,
|
||||||
|
alt_model_flag,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
jammered = false,
|
jammered = false,
|
||||||
obj.ExoSuit,
|
obj.ExoSuit,
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0L,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
val ab : (Boolean,Int)=>CharacterAppearanceB = CharacterAppearanceB(
|
||||||
|
0L,
|
||||||
outfit_name = "",
|
outfit_name = "",
|
||||||
outfit_logo = 0,
|
outfit_logo = 0,
|
||||||
|
false,
|
||||||
obj.isBackpack,
|
obj.isBackpack,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
facingPitch = obj.Orientation.y,
|
facingPitch = obj.Orientation.y,
|
||||||
facingYawUpper = obj.FacingYawUpper,
|
facingYawUpper = obj.FacingYawUpper,
|
||||||
lfs = true,
|
lfs = true,
|
||||||
GrenadeState.None,
|
GrenadeState.None,
|
||||||
is_cloaking = false,
|
obj.Cloaked,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
charging_pose = false,
|
charging_pose = false,
|
||||||
on_zipline = None,
|
false,
|
||||||
RibbonBars()
|
on_zipline = None
|
||||||
)
|
)
|
||||||
|
CharacterAppearanceData(aa, ab, RibbonBars())
|
||||||
}
|
}
|
||||||
|
|
||||||
def MakeCharacterData(obj : Player) : (Boolean,Boolean)=>CharacterData = {
|
def MakeCharacterData(obj : Player) : (Boolean,Boolean)=>CharacterData = {
|
||||||
val MaxArmor = obj.MaxArmor
|
val MaxArmor = obj.MaxArmor
|
||||||
CharacterData(
|
CharacterData(
|
||||||
255 * obj.Health / obj.MaxHealth, //TODO not precise
|
255 * obj.Health / obj.MaxHealth,
|
||||||
if(MaxArmor == 0) {
|
if(MaxArmor == 0) {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
255 * obj.Armor / MaxArmor
|
255 * obj.Armor / MaxArmor
|
||||||
}, //TODO not precise
|
},
|
||||||
DressBattleRank(obj),
|
DressBattleRank(obj),
|
||||||
|
0,
|
||||||
DressCommandRank(obj),
|
DressCommandRank(obj),
|
||||||
MakeImplantEffectList(obj.Implants),
|
MakeImplantEffectList(obj.Implants),
|
||||||
MakeCosmetics(obj.BEP)
|
MakeCosmetics(obj.BEP)
|
||||||
|
|
@ -101,20 +124,32 @@ object AvatarConverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
def MakeDetailedCharacterData(obj : Player) : (Option[Int])=>DetailedCharacterData = {
|
def MakeDetailedCharacterData(obj : Player) : (Option[Int])=>DetailedCharacterData = {
|
||||||
DetailedCharacterData(
|
val bep = obj.BEP
|
||||||
obj.BEP,
|
val ba : DetailedCharacterA = DetailedCharacterA(
|
||||||
|
bep,
|
||||||
obj.CEP,
|
obj.CEP,
|
||||||
obj.MaxHealth,
|
0L, 0L, 0L,
|
||||||
obj.Health,
|
obj.MaxHealth, obj.Health,
|
||||||
|
false,
|
||||||
obj.Armor,
|
obj.Armor,
|
||||||
obj.MaxStamina,
|
0L,
|
||||||
obj.Stamina,
|
obj.MaxStamina, obj.Stamina,
|
||||||
obj.Certifications.toList.sortBy(_.id), //TODO is sorting necessary?
|
0, 0, 0L,
|
||||||
|
List(0, 0, 0, 0, 0, 0),
|
||||||
|
obj.Certifications.toList.sortBy(_.id) //TODO is sorting necessary?
|
||||||
|
)
|
||||||
|
val bb : (Long, Option[Int])=>DetailedCharacterB = DetailedCharacterB(
|
||||||
|
None,
|
||||||
MakeImplantEntries(obj),
|
MakeImplantEntries(obj),
|
||||||
|
Nil, Nil,
|
||||||
firstTimeEvents = List.empty[String], //TODO fte list
|
firstTimeEvents = List.empty[String], //TODO fte list
|
||||||
tutorials = List.empty[String], //TODO tutorial list
|
tutorials = List.empty[String], //TODO tutorial list
|
||||||
MakeCosmetics(obj.BEP)
|
0L, 0L, 0L, 0L, 0L,
|
||||||
|
Some(DCDExtra2(0, 0)),
|
||||||
|
Nil, Nil, false,
|
||||||
|
MakeCosmetics(bep)
|
||||||
)
|
)
|
||||||
|
(pad_length : Option[Int]) => DetailedCharacterData(ba, bb(bep, pad_length))(pad_length)
|
||||||
}
|
}
|
||||||
|
|
||||||
def MakeInventoryData(obj : Player) : InventoryData = {
|
def MakeInventoryData(obj : Player) : InventoryData = {
|
||||||
|
|
@ -184,7 +219,7 @@ object AvatarConverter {
|
||||||
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = {
|
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = {
|
||||||
val numImplants : Int = DetailedCharacterData.numberOfImplantSlots(obj.BEP)
|
val numImplants : Int = DetailedCharacterData.numberOfImplantSlots(obj.BEP)
|
||||||
val implants = obj.Implants
|
val implants = obj.Implants
|
||||||
obj.Implants.map({ case(implant, initialization, active) =>
|
obj.Implants.map({ case(implant, initialization, _) =>
|
||||||
if(initialization == 0) {
|
if(initialization == 0) {
|
||||||
ImplantEntry(implant, None)
|
ImplantEntry(implant, None)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter
|
||||||
import net.psforever.objects.{EquipmentSlot, Player}
|
import net.psforever.objects.{EquipmentSlot, Player}
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
import net.psforever.types.{CharacterVoice, GrenadeState, ImplantType}
|
import net.psforever.types.{CertificationType, CharacterVoice, GrenadeState, ImplantType}
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.util.{Failure, Success, Try}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
@ -22,20 +22,7 @@ class CharacterSelectConverter extends AvatarConverter {
|
||||||
DetailedPlayerData.apply(
|
DetailedPlayerData.apply(
|
||||||
PlacementData(0, 0, 0),
|
PlacementData(0, 0, 0),
|
||||||
MakeAppearanceData(obj),
|
MakeAppearanceData(obj),
|
||||||
DetailedCharacterData(
|
MakeDetailedCharacterData(obj),
|
||||||
obj.BEP,
|
|
||||||
obj.CEP,
|
|
||||||
healthMax = 1,
|
|
||||||
health = 1,
|
|
||||||
armor = 0,
|
|
||||||
staminaMax = 1,
|
|
||||||
stamina = 1,
|
|
||||||
certs = Nil,
|
|
||||||
MakeImplantEntries(obj), //necessary for correct stream length
|
|
||||||
firstTimeEvents = Nil,
|
|
||||||
tutorials = Nil,
|
|
||||||
AvatarConverter.MakeCosmetics(obj.BEP)
|
|
||||||
),
|
|
||||||
InventoryData(recursiveMakeHolsters(obj.Holsters().iterator)),
|
InventoryData(recursiveMakeHolsters(obj.Holsters().iterator)),
|
||||||
AvatarConverter.GetDrawnSlot(obj)
|
AvatarConverter.GetDrawnSlot(obj)
|
||||||
)
|
)
|
||||||
|
|
@ -49,23 +36,73 @@ class CharacterSelectConverter extends AvatarConverter {
|
||||||
* @return the resulting `CharacterAppearanceData`
|
* @return the resulting `CharacterAppearanceData`
|
||||||
*/
|
*/
|
||||||
private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
||||||
CharacterAppearanceData(
|
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
||||||
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, CharacterVoice.Mute),
|
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, CharacterVoice.Mute),
|
||||||
black_ops = false,
|
black_ops = false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
jammered = false,
|
jammered = false,
|
||||||
obj.ExoSuit,
|
obj.ExoSuit,
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0L,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
val ab : (Boolean,Int)=>CharacterAppearanceB = CharacterAppearanceB(
|
||||||
|
0L,
|
||||||
outfit_name = "",
|
outfit_name = "",
|
||||||
outfit_logo = 0,
|
outfit_logo = 0,
|
||||||
|
false,
|
||||||
backpack = false,
|
backpack = false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
facingPitch = 0,
|
facingPitch = 0,
|
||||||
facingYawUpper = 0,
|
facingYawUpper = 0,
|
||||||
lfs = true,
|
lfs = false,
|
||||||
GrenadeState.None,
|
GrenadeState.None,
|
||||||
is_cloaking = false,
|
obj.Cloaked,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
charging_pose = false,
|
charging_pose = false,
|
||||||
on_zipline = None,
|
false,
|
||||||
RibbonBars()
|
on_zipline = None
|
||||||
)
|
)
|
||||||
|
CharacterAppearanceData(aa, ab, RibbonBars())
|
||||||
|
}
|
||||||
|
|
||||||
|
private def MakeDetailedCharacterData(obj : Player) : (Option[Int]=>DetailedCharacterData) = {
|
||||||
|
val bep = obj.BEP
|
||||||
|
val ba : DetailedCharacterA = DetailedCharacterA(
|
||||||
|
bep,
|
||||||
|
obj.CEP,
|
||||||
|
0L, 0L, 0L,
|
||||||
|
1, 1,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
0L,
|
||||||
|
1, 1,
|
||||||
|
0, 0, 0L,
|
||||||
|
List(0, 0, 0, 0, 0, 0),
|
||||||
|
certs = List.empty[CertificationType.Value]
|
||||||
|
)
|
||||||
|
val bb : (Long, Option[Int])=>DetailedCharacterB = DetailedCharacterB(
|
||||||
|
None,
|
||||||
|
MakeImplantEntries(obj), //necessary for correct stream length
|
||||||
|
Nil, Nil,
|
||||||
|
firstTimeEvents = List.empty[String],
|
||||||
|
tutorials = List.empty[String],
|
||||||
|
0L, 0L, 0L, 0L, 0L,
|
||||||
|
Some(DCDExtra2(0, 0)),
|
||||||
|
Nil, Nil, false,
|
||||||
|
AvatarConverter.MakeCosmetics(bep)
|
||||||
|
)
|
||||||
|
(pad_length : Option[Int]) => DetailedCharacterData(ba, bb(bep, pad_length))(pad_length)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter
|
||||||
import net.psforever.objects.{EquipmentSlot, Player}
|
import net.psforever.objects.{EquipmentSlot, Player}
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
import net.psforever.types.{CharacterGender, CharacterVoice, GrenadeState, Vector3}
|
import net.psforever.types._
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.util.{Failure, Success, Try}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
@ -18,20 +18,7 @@ class CorpseConverter extends AvatarConverter {
|
||||||
DetailedPlayerData.apply(
|
DetailedPlayerData.apply(
|
||||||
PlacementData(obj.Position, Vector3(0,0, obj.Orientation.z)),
|
PlacementData(obj.Position, Vector3(0,0, obj.Orientation.z)),
|
||||||
MakeAppearanceData(obj),
|
MakeAppearanceData(obj),
|
||||||
DetailedCharacterData(
|
MakeDetailedCharacterData(obj),
|
||||||
bep = 0,
|
|
||||||
cep = 0,
|
|
||||||
healthMax = 0,
|
|
||||||
health = 0,
|
|
||||||
armor = 0,
|
|
||||||
staminaMax = 0,
|
|
||||||
stamina = 0,
|
|
||||||
certs = Nil,
|
|
||||||
implants = Nil,
|
|
||||||
firstTimeEvents = Nil,
|
|
||||||
tutorials = Nil,
|
|
||||||
cosmetics = None
|
|
||||||
),
|
|
||||||
InventoryData((MakeHolsters(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)),
|
InventoryData((MakeHolsters(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)),
|
||||||
DrawnSlot.None
|
DrawnSlot.None
|
||||||
)
|
)
|
||||||
|
|
@ -44,23 +31,72 @@ class CorpseConverter extends AvatarConverter {
|
||||||
* @return the resulting `CharacterAppearanceData`
|
* @return the resulting `CharacterAppearanceData`
|
||||||
*/
|
*/
|
||||||
private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
||||||
CharacterAppearanceData(
|
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
||||||
BasicCharacterData(obj.Name, obj.Faction, CharacterGender.Male, 0, CharacterVoice.Mute),
|
BasicCharacterData(obj.Name, obj.Faction, CharacterGender.Male, 0, CharacterVoice.Mute),
|
||||||
black_ops = false,
|
black_ops = false,
|
||||||
|
altModel = true,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
jammered = false,
|
jammered = false,
|
||||||
obj.ExoSuit,
|
obj.ExoSuit,
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0L,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
val ab : (Boolean,Int)=>CharacterAppearanceB = CharacterAppearanceB(
|
||||||
|
0L,
|
||||||
outfit_name = "",
|
outfit_name = "",
|
||||||
outfit_logo = 0,
|
outfit_logo = 0,
|
||||||
|
false,
|
||||||
backpack = true,
|
backpack = true,
|
||||||
facingPitch = obj.Orientation.y, //TODO is this important?
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
facingPitch = 0,
|
||||||
facingYawUpper = 0,
|
facingYawUpper = 0,
|
||||||
lfs = true,
|
lfs = false,
|
||||||
GrenadeState.None,
|
GrenadeState.None,
|
||||||
is_cloaking = false,
|
is_cloaking = false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
charging_pose = false,
|
charging_pose = false,
|
||||||
on_zipline = None,
|
false,
|
||||||
RibbonBars()
|
on_zipline = None
|
||||||
)
|
)
|
||||||
|
CharacterAppearanceData(aa, ab, RibbonBars())
|
||||||
|
}
|
||||||
|
|
||||||
|
private def MakeDetailedCharacterData(obj : Player) : (Option[Int]=>DetailedCharacterData) = {
|
||||||
|
val ba : DetailedCharacterA = DetailedCharacterA(
|
||||||
|
bep = 0L,
|
||||||
|
cep = 0L,
|
||||||
|
0L, 0L, 0L,
|
||||||
|
0, 0,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
0L,
|
||||||
|
0, 0,
|
||||||
|
0, 0, 0L,
|
||||||
|
List(0, 0, 0, 0, 0, 0),
|
||||||
|
certs = List.empty[CertificationType.Value]
|
||||||
|
)
|
||||||
|
val bb : (Long, Option[Int])=>DetailedCharacterB = DetailedCharacterB(
|
||||||
|
None,
|
||||||
|
implants = List.empty[ImplantEntry],
|
||||||
|
Nil, Nil,
|
||||||
|
firstTimeEvents = List.empty[String],
|
||||||
|
tutorials = List.empty[String],
|
||||||
|
0L, 0L, 0L, 0L, 0L,
|
||||||
|
Some(DCDExtra2(0, 0)),
|
||||||
|
Nil, Nil, false,
|
||||||
|
cosmetics = None
|
||||||
|
)
|
||||||
|
(pad_length : Option[Int]) => DetailedCharacterData(ba, bb(0, pad_length))(pad_length)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,7 @@ abstract class IdentifiableEntity extends Identifiable {
|
||||||
private val container : GUIDContainable = GUIDContainer()
|
private val container : GUIDContainable = GUIDContainer()
|
||||||
private var current : GUIDContainable = IdentifiableEntity.noGUIDContainer
|
private var current : GUIDContainable = IdentifiableEntity.noGUIDContainer
|
||||||
|
|
||||||
def HasGUID : Boolean = {
|
def HasGUID : Boolean = current ne IdentifiableEntity.noGUIDContainer
|
||||||
try {
|
|
||||||
GUID
|
|
||||||
true
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
case _ : NoGUIDException =>
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def GUID : PlanetSideGUID = current.GUID
|
def GUID : PlanetSideGUID = current.GUID
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,17 +44,15 @@ class UniqueNumberSystem(private val guid : NumberPoolHub, private val poolActor
|
||||||
def receive : Receive = {
|
def receive : Receive = {
|
||||||
case Register(obj, Some(pname), None, call) =>
|
case Register(obj, Some(pname), None, call) =>
|
||||||
val callback = call.getOrElse(sender())
|
val callback = call.getOrElse(sender())
|
||||||
try {
|
if(obj.HasGUID) {
|
||||||
obj.GUID //stop if object already has a GUID; sometimes this happens
|
|
||||||
AlreadyRegistered(obj, pname)
|
AlreadyRegistered(obj, pname)
|
||||||
callback ! Success(obj)
|
callback ! Success(obj)
|
||||||
}
|
}
|
||||||
catch {
|
else {
|
||||||
case _ : Exception =>
|
val id : Long = index
|
||||||
val id : Long = index
|
index += 1
|
||||||
index += 1
|
requestQueue += id -> UniqueNumberSystem.GUIDRequest(obj, pname, callback)
|
||||||
requestQueue += id -> UniqueNumberSystem.GUIDRequest(obj, pname, callback)
|
RegistrationProcess(pname, id)
|
||||||
RegistrationProcess(pname, id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//this message is automatically sent by NumberPoolActor
|
//this message is automatically sent by NumberPoolActor
|
||||||
|
|
|
||||||
|
|
@ -43,15 +43,16 @@ object UniformStyle extends Enumeration {
|
||||||
/**
|
/**
|
||||||
* A representation of a portion of an avatar's `ObjectCreateDetailedMessage` packet data.<br>
|
* A representation of a portion of an avatar's `ObjectCreateDetailedMessage` packet data.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* This densely-packed information outlines most of the specifics required to depict some other player's character.
|
* This 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.
|
* 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.
|
* For that reason, the character is mostly for presentation purposes, rather than really being fleshed-out.
|
||||||
* Of the inventory for this character, only the initial five weapon slots are defined.<br>
|
* Of the inventory for this character, only the initial five weapon slots are defined.
|
||||||
* <br>
|
|
||||||
* In the "backend of the client," the character produced by this data is no different
|
* 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.
|
* 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,
|
* In terms of equipment and complicated features common to an avatar character, however,
|
||||||
* any user would find this character ill-equipped.
|
* any user would find this character ill-equipped.
|
||||||
|
* @see `DetailedCharacterData`
|
||||||
|
* @see `Cosmetics`
|
||||||
* @param health the amount of health the player has, as a percentage of a filled bar;
|
* @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;
|
* 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;
|
* when 0% (less than 3 of 255), the player will collapse into a death pose on the ground;
|
||||||
|
|
@ -74,8 +75,6 @@ object UniformStyle extends Enumeration {
|
||||||
* the alternate model bit should be flipped
|
* the alternate model bit should be flipped
|
||||||
* @param is_seated this player character is seated in a vehicle or mounted to some other object;
|
* @param is_seated this player character is seated in a vehicle or mounted to some other object;
|
||||||
* alternate format for data parsing applies
|
* alternate format for data parsing applies
|
||||||
* @see `DetailedCharacterData`<br>
|
|
||||||
* `CharacterAppearanceData`
|
|
||||||
*/
|
*/
|
||||||
final case class CharacterData(health : Int,
|
final case class CharacterData(health : Int,
|
||||||
armor : Int,
|
armor : Int,
|
||||||
|
|
@ -88,7 +87,6 @@ final case class CharacterData(health : Int,
|
||||||
is_seated : Boolean) extends ConstructorData {
|
is_seated : Boolean) extends ConstructorData {
|
||||||
|
|
||||||
override def bitsize : Long = {
|
override def bitsize : Long = {
|
||||||
//factor guard bool values into the base size, not its corresponding optional field
|
|
||||||
val seatedSize = if(is_seated) { 0 } else { 16 }
|
val seatedSize = if(is_seated) { 0 } else { 16 }
|
||||||
val effectsSize : Long = implant_effects.length * 4L
|
val effectsSize : Long = implant_effects.length * 4L
|
||||||
val cosmeticsSize : Long = if(cosmetics.isDefined) { cosmetics.get.bitsize } else { 0L }
|
val cosmeticsSize : Long = if(cosmetics.isDefined) { cosmetics.get.bitsize } else { 0L }
|
||||||
|
|
@ -98,7 +96,7 @@ final case class CharacterData(health : Int,
|
||||||
|
|
||||||
object CharacterData extends Marshallable[CharacterData] {
|
object CharacterData extends Marshallable[CharacterData] {
|
||||||
/**
|
/**
|
||||||
* An overloaded constructor for `CharacterData` that allows for a not-optional inventory.
|
* An overloaded constructor for `CharacterData`.
|
||||||
* @param health the amount of health the player has, as a percentage of a filled bar
|
* @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 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 uniform the level of upgrade to apply to the player's base uniform
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ import scala.annotation.tailrec
|
||||||
/**
|
/**
|
||||||
* An entry in the `List` of valid implant slots in `DetailedCharacterData`.
|
* An entry in the `List` of valid implant slots in `DetailedCharacterData`.
|
||||||
* @param implant the type of implant
|
* @param implant the type of implant
|
||||||
* technically, this is unconfirmed
|
* @param initialization the amount of time necessary until this implant is ready to be activated;
|
||||||
|
* technically, this is unconfirmed
|
||||||
* @param active whether this implant is turned on;
|
* @param active whether this implant is turned on;
|
||||||
* technically, this is unconfirmed
|
* technically, this is unconfirmed
|
||||||
* @see `ImplantType`
|
* @see `ImplantType`
|
||||||
|
|
@ -33,11 +34,21 @@ object ImplantEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param unk1 na
|
||||||
|
* @param unk2 na
|
||||||
|
*/
|
||||||
final case class DCDExtra1(unk1 : String,
|
final case class DCDExtra1(unk1 : String,
|
||||||
unk2 : Int) extends StreamBitSize {
|
unk2 : Int) extends StreamBitSize {
|
||||||
override def bitsize : Long = 16L + StreamBitSize.stringBitSize(unk1)
|
override def bitsize : Long = 16L + StreamBitSize.stringBitSize(unk1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param unk1 an
|
||||||
|
* @param unk2 na
|
||||||
|
*/
|
||||||
final case class DCDExtra2(unk1 : Int,
|
final case class DCDExtra2(unk1 : Int,
|
||||||
unk2 : Int) extends StreamBitSize {
|
unk2 : Int) extends StreamBitSize {
|
||||||
override def bitsize : Long = 13L
|
override def bitsize : Long = 13L
|
||||||
|
|
@ -124,10 +135,8 @@ final case class DetailedCharacterB(unk1 : Option[Long],
|
||||||
//implant list
|
//implant list
|
||||||
val implantSize : Long = implants.foldLeft(0L)(_ + _.bitsize)
|
val implantSize : Long = implants.foldLeft(0L)(_ + _.bitsize)
|
||||||
//fte list
|
//fte list
|
||||||
val fteLen = firstTimeEvents.size
|
|
||||||
val eventListSize : Long = firstTimeEvents.foldLeft(0L)(_ + StreamBitSize.stringBitSize(_))
|
val eventListSize : Long = firstTimeEvents.foldLeft(0L)(_ + StreamBitSize.stringBitSize(_))
|
||||||
//tutorial list
|
//tutorial list
|
||||||
val tutLen = tutorials.size
|
|
||||||
val tutorialListSize : Long = tutorials.foldLeft(0L)(_ + StreamBitSize.stringBitSize(_))
|
val tutorialListSize : Long = tutorials.foldLeft(0L)(_ + StreamBitSize.stringBitSize(_))
|
||||||
val unk2Len = unk2.size
|
val unk2Len = unk2.size
|
||||||
val unk3Len = unk3.size
|
val unk3Len = unk3.size
|
||||||
|
|
@ -151,8 +160,8 @@ final case class DetailedCharacterB(unk1 : Option[Long],
|
||||||
val paddingSize : Int =
|
val paddingSize : Int =
|
||||||
DetailedCharacterData.paddingCalculations(pad_length, implants, Nil)(unk2Len) + /* unk2 */
|
DetailedCharacterData.paddingCalculations(pad_length, implants, Nil)(unk2Len) + /* unk2 */
|
||||||
DetailedCharacterData.paddingCalculations(pad_length, implants, List(unk2))(unk3Len) + /* unk3 */
|
DetailedCharacterData.paddingCalculations(pad_length, implants, List(unk2))(unk3Len) + /* unk3 */
|
||||||
DetailedCharacterData.paddingCalculations(pad_length, implants, List(unk3, unk2))(fteLen) + /* firstTimeEvents */
|
DetailedCharacterData.paddingCalculations(pad_length, implants, List(unk3, unk2))(firstTimeEvents.length) + /* firstTimeEvents */
|
||||||
DetailedCharacterData.paddingCalculations(pad_length, implants, List(firstTimeEvents, unk3, unk2))(tutLen) + /* tutorials */
|
DetailedCharacterData.paddingCalculations(pad_length, implants, List(firstTimeEvents, unk3, unk2))(tutorials.size) + /* tutorials */
|
||||||
DetailedCharacterData.paddingCalculations(
|
DetailedCharacterData.paddingCalculations(
|
||||||
DetailedCharacterData.displaceByUnk9(pad_length, unk9, 5),
|
DetailedCharacterData.displaceByUnk9(pad_length, unk9, 5),
|
||||||
implants,
|
implants,
|
||||||
|
|
@ -245,15 +254,15 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
val activeBool : Boolean = n != 0
|
val activeBool : Boolean = n != 0
|
||||||
ImplantEntry(ImplantType(implant), None, activeBool) //TODO catch potential NoSuchElementException?
|
ImplantEntry(ImplantType(implant), None, activeBool) //TODO catch potential NoSuchElementException?
|
||||||
|
|
||||||
case implant :: false :: extra :: HNil => //unintialized (timer), inactive
|
case implant :: false :: extra :: HNil => //uninitialized (timer), inactive
|
||||||
ImplantEntry(ImplantType(implant), Some(extra), false) //TODO catch potential NoSuchElementException?
|
ImplantEntry(ImplantType(implant), Some(extra), false) //TODO catch potential NoSuchElementException?
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case ImplantEntry(implant, None, n) => //initialized (no timer), active/inactive?
|
case ImplantEntry(implant, None, n) => //initialized (no timer), active/inactive?
|
||||||
val activeInt : Int = if(n) { 1 } else { 0 }
|
val activeInt : Int = if(n) { 1 } else { 0 }
|
||||||
implant.id :: true :: activeInt :: HNil
|
implant.id :: true :: activeInt :: HNil
|
||||||
|
|
||||||
case ImplantEntry(implant, Some(extra), _) => //unintialized (timer), inactive
|
case ImplantEntry(implant, Some(extra), _) => //uninitialized (timer), inactive
|
||||||
implant.id :: false :: extra :: HNil
|
implant.id :: false :: extra :: HNil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -279,6 +288,10 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `Codec` for a `List` of `DCDExtra1` objects.
|
||||||
|
* The first entry contains a padded `String` so it must be processed different from the remainder.
|
||||||
|
*/
|
||||||
private def dcd_list_codec(padFunc : (Long)=>Int) : Codec[List[DCDExtra1]] = (
|
private def dcd_list_codec(padFunc : (Long)=>Int) : Codec[List[DCDExtra1]] = (
|
||||||
uint8 >>:~ { size =>
|
uint8 >>:~ { size =>
|
||||||
conditional(size > 0, dcd_extra1_codec(padFunc(size))) ::
|
conditional(size > 0, dcd_extra1_codec(padFunc(size))) ::
|
||||||
|
|
@ -301,6 +314,10 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `Codec` for entries in the `List` of `DCDExtra1` objects.
|
||||||
|
* The first entry's size of 80 characters is hard-set by the client.
|
||||||
|
*/
|
||||||
private def dcd_extra1_codec(pad : Int) : Codec[DCDExtra1] = (
|
private def dcd_extra1_codec(pad : Int) : Codec[DCDExtra1] = (
|
||||||
("unk1" | PacketHelpers.encodedStringAligned(pad)) ::
|
("unk1" | PacketHelpers.encodedStringAligned(pad)) ::
|
||||||
("unk2" | uint16L)
|
("unk2" | uint16L)
|
||||||
|
|
@ -315,6 +332,12 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A common `Codec` for a `List` of `String` objects
|
||||||
|
* used for first time events list and for the tutorials list.
|
||||||
|
* The first entry contains a padded `String` so it must be processed different from the remainder.
|
||||||
|
* @param padFunc a curried function awaiting the extracted length of the current `List`
|
||||||
|
*/
|
||||||
private def eventsListCodec(padFunc : (Long)=>Int) : Codec[List[String]] = (
|
private def eventsListCodec(padFunc : (Long)=>Int) : Codec[List[String]] = (
|
||||||
uint32L >>:~ { size =>
|
uint32L >>:~ { size =>
|
||||||
conditional(size > 0, PacketHelpers.encodedStringAligned(padFunc(size))) ::
|
conditional(size > 0, PacketHelpers.encodedStringAligned(padFunc(size))) ::
|
||||||
|
|
@ -337,11 +360,22 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `Codec` for a `DCDExtra2` object.
|
||||||
|
*/
|
||||||
private val dcd_extra2_codec : Codec[DCDExtra2] = (
|
private val dcd_extra2_codec : Codec[DCDExtra2] = (
|
||||||
uint(5) ::
|
uint(5) ::
|
||||||
uint8L
|
uint8L
|
||||||
).as[DCDExtra2]
|
).as[DCDExtra2]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `Codec` for a `List` of `String` objects.
|
||||||
|
* The first entry contains a padded `String` so it must be processed different from the remainder.
|
||||||
|
* The padding length is the conclusion of the summation of all the bits up until the point of this `String` object.
|
||||||
|
* Additionally, the length of this current string is also a necessary consideration.
|
||||||
|
* @see `paddingCalculations`
|
||||||
|
* @param padFunc a curried function awaiting the extracted length of the current `List` and will count the padding bits
|
||||||
|
*/
|
||||||
private def unkBCodec(padFunc : (Long)=>Int) : Codec[List[String]] = (
|
private def unkBCodec(padFunc : (Long)=>Int) : Codec[List[String]] = (
|
||||||
uint16L >>:~ { size =>
|
uint16L >>:~ { size =>
|
||||||
conditional(size > 0, PacketHelpers.encodedStringAligned(padFunc(size))) ::
|
conditional(size > 0, PacketHelpers.encodedStringAligned(padFunc(size))) ::
|
||||||
|
|
@ -364,11 +398,25 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suport function that obtains the "absolute list value" of an `Option` object.
|
||||||
|
* @param opt the `Option` object
|
||||||
|
* @return if defined, returns a `List` of the `Option` object's contents;
|
||||||
|
* if undefined (`None`), returns an empty list
|
||||||
|
*/
|
||||||
def optToList(opt : Option[Any]) : List[Any] = opt match {
|
def optToList(opt : Option[Any]) : List[Any] = opt match {
|
||||||
case Some(o) => List(o)
|
case Some(o) => List(o)
|
||||||
case None => Nil
|
case None => Nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A very specific `Option` object addition function.
|
||||||
|
* If a condition is met, the current `Optional` value is incremented by a specific amount.
|
||||||
|
* @param start the original amount
|
||||||
|
* @param test the test on whether to add to `start`
|
||||||
|
* @param value how much to add to `start`
|
||||||
|
* @return the amount after testing
|
||||||
|
*/
|
||||||
def displaceByUnk9(start : Option[Int], test : Option[Any], value : Int) : Option[Int] = test match {
|
def displaceByUnk9(start : Option[Int], test : Option[Any], value : Int) : Option[Int] = test match {
|
||||||
case Some(_) =>
|
case Some(_) =>
|
||||||
Some(start.getOrElse(0) + value)
|
Some(start.getOrElse(0) + value)
|
||||||
|
|
@ -376,18 +424,56 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
start
|
start
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `List` of bit distances between different sets of `String` objects in the `DetailedCharacterData` `Codec`
|
||||||
|
* in reverse order of encountered `String` fields (later to earlier).
|
||||||
|
* The distances are not the actual lengths but are modulo eight.
|
||||||
|
* Specific strings include (the contents of):<br>
|
||||||
|
* - `unk9` (as a `List` object)<br>
|
||||||
|
* - `tutorials`<br>
|
||||||
|
* - `firstTimeEvents`<br>
|
||||||
|
* - `unk3`<br>
|
||||||
|
* - `unk2`
|
||||||
|
*/
|
||||||
private val displacementPerEntry : List[Int] = List(7, 0, 0, 0, 0)
|
private val displacementPerEntry : List[Int] = List(7, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A curried function to calculate a cumulative padding value
|
||||||
|
* for whichever of the groups of `List` objects of `String` objects are found in a `DetailedCharacterData` object.
|
||||||
|
* Defines the expected base value - the starting value for determining the padding.
|
||||||
|
* The specific `String` object being considered is determined by the number of input lists.
|
||||||
|
* @see `paddingCalculations(Int, Option[Int], List[ImplantEntry], List[List[Any]])(Long)`
|
||||||
|
* @param contextOffset an inherited modification of the `base` padding value
|
||||||
|
* @param implants the list of implants in the stream
|
||||||
|
* @param prevLists all of the important previous lists
|
||||||
|
* @param currListLen the length of the current list
|
||||||
|
* @return the padding value for the target list
|
||||||
|
*/
|
||||||
def paddingCalculations(contextOffset : Option[Int], implants : List[ImplantEntry], prevLists : List[List[Any]])(currListLen : Long) : Int = {
|
def paddingCalculations(contextOffset : Option[Int], implants : List[ImplantEntry], prevLists : List[List[Any]])(currListLen : Long) : Int = {
|
||||||
paddingCalculations(3, contextOffset, implants, prevLists)(currListLen)
|
paddingCalculations(3, contextOffset, implants, prevLists)(currListLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A curried function to calculate a cumulative padding value
|
||||||
|
* for whichever of the groups of `List` objects of `String` objects are found in a `DetailedCharacterData` object.
|
||||||
|
* The specific `String` object being considered is determined by the number of input lists.
|
||||||
|
* @see `paddingCalculations(Option[Int], List[ImplantEntry], List[List[Any/]/])(Long)`
|
||||||
|
* @param base the starting value with no implant entries, or bits from context
|
||||||
|
* @param contextOffset an inherited modification of the `base` padding value
|
||||||
|
* @param implants the list of implants in the stream
|
||||||
|
* @param prevLists all of the important previous lists
|
||||||
|
* @param currListLen the length of the current list
|
||||||
|
* @throws Exception if the number of input lists (`prevLists`) exceeds the number of expected bit distances between known lists
|
||||||
|
* @return the padding value for the target list;
|
||||||
|
* a value clamped between 0 and 7
|
||||||
|
*/
|
||||||
def paddingCalculations(base : Int, contextOffset : Option[Int], implants : List[ImplantEntry], prevLists : List[List[Any]])(currListLen : Long) : Int = {
|
def paddingCalculations(base : Int, contextOffset : Option[Int], implants : List[ImplantEntry], prevLists : List[List[Any]])(currListLen : Long) : Int = {
|
||||||
if(currListLen > 0) {
|
if(prevLists.length > displacementPerEntry.length) {
|
||||||
//the offset with no implant entries, or bits from context
|
throw new Exception("mismatched number of input lists compared to bit distances")
|
||||||
|
}
|
||||||
|
else if(currListLen > 0) {
|
||||||
//displacement into next byte of the content field of the first relevant string without padding
|
//displacement into next byte of the content field of the first relevant string without padding
|
||||||
val baseResult : Int = base + contextOffset.getOrElse(0) + implants.foldLeft(0L)(_ + _.bitsize).toInt
|
val baseResult : Int = base + contextOffset.getOrElse(0) + implants.foldLeft(0L)(_ + _.bitsize).toInt
|
||||||
|
|
||||||
val displacementResult : Int = (if(prevLists.isEmpty) {
|
val displacementResult : Int = (if(prevLists.isEmpty) {
|
||||||
baseResult
|
baseResult
|
||||||
}
|
}
|
||||||
|
|
@ -414,21 +500,6 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * The padding value of the first entry in either of two byte-aligned `List` structures.
|
|
||||||
// * @param implants implant entries
|
|
||||||
// * @return the pad length in bits `0 <= n < 8`
|
|
||||||
// */
|
|
||||||
// def implantFieldPadding(implants : List[ImplantEntry], varBit : Option[Int] = None) : Int = {
|
|
||||||
// val base : Int = 5 //the offset with no implant entries
|
|
||||||
// val baseOffset : Int = base - varBit.getOrElse(0)
|
|
||||||
// val resultA = if(baseOffset < 0) { 8 - baseOffset } else { baseOffset % 8 }
|
|
||||||
//
|
|
||||||
// val implantOffset = implants.foldLeft(0L)(_ + _.bitsize).toInt
|
|
||||||
// val resultB : Int = resultA - (implantOffset % 8)
|
|
||||||
// if(resultB < 0) { 8 + resultB } else { resultB }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Players with certain battle rank will always have a certain number of implant slots.
|
* Players with certain battle rank will always have a certain number of implant slots.
|
||||||
* The encoding requires it.
|
* The encoding requires it.
|
||||||
|
|
@ -447,6 +518,13 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By comparing the battle experience points to a fixed number of points,
|
||||||
|
* determine if the player is at least battle rank 24.
|
||||||
|
* Important things happen if the player is at least battle rank 24 ...
|
||||||
|
* @param bep the battle experience points being compared
|
||||||
|
* @return `true`, if the battle experience points are enough to be a player of the esteemed battle rank
|
||||||
|
*/
|
||||||
def isBR24(bep : Long) : Boolean = bep > 2286230
|
def isBR24(bep : Long) : Boolean = bep > 2286230
|
||||||
|
|
||||||
val a_codec : Codec[DetailedCharacterA] = (
|
val a_codec : Codec[DetailedCharacterA] = (
|
||||||
|
|
@ -462,27 +540,27 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
("unk5" | uint32) :: //endianness?
|
("unk5" | uint32) :: //endianness?
|
||||||
("staminaMax" | uint16L) ::
|
("staminaMax" | uint16L) ::
|
||||||
("stamina" | uint16L) ::
|
("stamina" | uint16L) ::
|
||||||
//TODO optional 32u-something here; see ps.c: line#1070692
|
conditional(false, uint32L) :: //see ps.c: sub_901150, line#1070692
|
||||||
("unk6" | uint16L) ::
|
("unk6" | uint16L) ::
|
||||||
("unk7" | uint(3)) ::
|
("unk7" | uint(3)) ::
|
||||||
("unk8" | uint32L) ::
|
("unk8" | uint32L) ::
|
||||||
("unk9" | PacketHelpers.listOfNSized(6, uint16L)) :: //always 6
|
("unk9" | PacketHelpers.listOfNSized(6, uint16L)) :: //always length of 6
|
||||||
("certs" | listOfN(uint8L, CertificationType.codec))
|
("certs" | listOfN(uint8L, CertificationType.codec))
|
||||||
).exmap[DetailedCharacterA] (
|
).exmap[DetailedCharacterA] (
|
||||||
{
|
{
|
||||||
case bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: u6 :: u7 :: u8 :: u9 :: certs :: HNil =>
|
case bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: None :: u6 :: u7 :: u8 :: u9 :: certs :: HNil =>
|
||||||
Attempt.successful(DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, u6, u7, u8, u9, certs))
|
Attempt.successful(DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, u6, u7, u8, u9, certs))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, u6, u7, u8, u9, certs) =>
|
case DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, u6, u7, u8, u9, certs) =>
|
||||||
Attempt.successful(
|
Attempt.successful(
|
||||||
bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: u6 :: u7 :: u8 :: u9 :: certs :: HNil
|
bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: None :: u6 :: u7 :: u8 :: u9 :: certs :: HNil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def b_codec(bep : Long, pad_length : Option[Int]) : Codec[DetailedCharacterB] = (
|
def b_codec(bep : Long, pad_length : Option[Int]) : Codec[DetailedCharacterB] = (
|
||||||
optional(bool, "unk1" | uint32L) :: //ask about sample CCRIDER
|
optional(bool, "unk1" | uint32L) ::
|
||||||
(("implants" | PacketHelpers.listOfNSized(numberOfImplantSlots(bep), implant_entry_codec)) >>:~ { implants =>
|
(("implants" | PacketHelpers.listOfNSized(numberOfImplantSlots(bep), implant_entry_codec)) >>:~ { implants =>
|
||||||
("unk2" | dcd_list_codec(paddingCalculations(pad_length, implants, Nil))) >>:~ { unk2 =>
|
("unk2" | dcd_list_codec(paddingCalculations(pad_length, implants, Nil))) >>:~ { unk2 =>
|
||||||
("unk3" | dcd_list_codec(paddingCalculations(pad_length, implants, List(unk2)))) >>:~ { unk3 =>
|
("unk3" | dcd_list_codec(paddingCalculations(pad_length, implants, List(unk2)))) >>:~ { unk3 =>
|
||||||
|
|
|
||||||
|
|
@ -21,15 +21,16 @@ import shapeless.{::, HNil}
|
||||||
* The presence or absence of position data as the first division creates a cascading effect
|
* 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.
|
* causing all of fields in the other two divisions to gain offsets.
|
||||||
* These offsets exist in the form of `String` and `List` padding.
|
* These offsets exist in the form of `String` and `List` padding.
|
||||||
* @see `DetailedCharacterData`<br>
|
* @see `CharacterAppearanceData`
|
||||||
* `InventoryData`<br>
|
* @see `DetailedCharacterData`
|
||||||
* `DrawnSlot`
|
* @see `InventoryData`
|
||||||
|
* @see `DrawnSlot`
|
||||||
* @param pos the optional position of the character in the world environment
|
* @param pos the optional position of the character in the world environment
|
||||||
* @param basic_appearance common fields regarding the the character's appearance
|
* @param basic_appearance common fields regarding the the character's appearance
|
||||||
* @param character_data the class-specific data that explains about the character
|
* @param character_data the class-specific data that discusses the character
|
||||||
* @param position_defined used by the `Codec` to seed the state of the optional `pos` field
|
* @param position_defined used to seed the state of the optional position fields
|
||||||
* @param inventory the player's full inventory
|
* @param inventory the player's full or partial (holsters-only) inventory
|
||||||
* @param drawn_slot the holster that is initially drawn
|
* @param drawn_slot the holster that is depicted as exposed, or "drawn"
|
||||||
*/
|
*/
|
||||||
final case class DetailedPlayerData(pos : Option[PlacementData],
|
final case class DetailedPlayerData(pos : Option[PlacementData],
|
||||||
basic_appearance : CharacterAppearanceData,
|
basic_appearance : CharacterAppearanceData,
|
||||||
|
|
@ -54,8 +55,8 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
* This constructor should be used for players that are mounted.
|
* This constructor should be used for players that are mounted.
|
||||||
* @param basic_appearance a curried function for the common fields regarding the the character's appearance
|
* @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 character_data a curried function for the class-specific data that explains about the character
|
||||||
* @param inventory the player's inventory
|
* @param inventory the player's full or partial (holsters-only) inventory
|
||||||
* @param drawn_slot the holster that is initially drawn;
|
* @param drawn_slot the holster that is depicted as exposed, or "drawn";
|
||||||
* technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
|
* technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
|
||||||
* @return a `DetailedPlayerData` object
|
* @return a `DetailedPlayerData` object
|
||||||
*/
|
*/
|
||||||
|
|
@ -70,7 +71,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
* This constructor should be used for players that are mounted.
|
* This constructor should be used for players that are mounted.
|
||||||
* @param basic_appearance a curried function for the common fields regarding the the character's appearance
|
* @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 character_data a curried function for the class-specific data that explains about the character
|
||||||
* @param drawn_slot the holster that is initially drawn;
|
* @param drawn_slot the holster that is depicted as exposed, or "drawn;"
|
||||||
* technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
|
* technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
|
||||||
* @return a `DetailedPlayerData` object
|
* @return a `DetailedPlayerData` object
|
||||||
*/
|
*/
|
||||||
|
|
@ -86,8 +87,8 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
* @param pos the optional position of the character in the world environment
|
* @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 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 character_data a curried function for the class-specific data that explains about the character
|
||||||
* @param inventory the player's inventory
|
* @param inventory the player's full or partial (holsters-only) inventory
|
||||||
* @param drawn_slot the holster that is initially drawn
|
* @param drawn_slot the holster that is depicted as exposed, or "drawn"
|
||||||
* @return a `DetailedPlayerData` object
|
* @return a `DetailedPlayerData` object
|
||||||
*/
|
*/
|
||||||
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
|
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
|
||||||
|
|
@ -102,7 +103,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
* @param pos the optional position of the character in the world environment
|
* @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 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 character_data a curried function for the class-specific data that explains about the character
|
||||||
* @param drawn_slot the holster that is initially drawn
|
* @param drawn_slot the holster that is depicted as exposed, or "drawn"
|
||||||
* @return a `DetailedPlayerData` object
|
* @return a `DetailedPlayerData` object
|
||||||
*/
|
*/
|
||||||
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
|
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -9,182 +9,236 @@ import org.specs2.mutable._
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
|
|
||||||
class MountedVehiclesTest extends Specification {
|
class MountedVehiclesTest extends Specification {
|
||||||
// val string_mosquito_seated =
|
val string_mosquito_seated =
|
||||||
// hex"17c70700009e2d410d8ed818f1a4017047f7ffbc6390ffbe01801cff00003c08791801d00000002340530063007200610077006e00790052" ++
|
hex"17c70700009e2d410d8ed818f1a4017047f7ffbc6390ffbe01801cff00003c08791801d00000002340530063007200610077006e00790052" ++
|
||||||
// hex"006f006e006e0069006500020b7e67b540404001000000000022b50100268042006c00610063006b00200042006500720065007400200041" ++
|
hex"006f006e006e0069006500020b7e67b540404001000000000022b50100268042006c00610063006b00200042006500720065007400200041" ++
|
||||||
// hex"0072006d006f007500720065006400200043006f00720070007300170040030050040003bc00000234040001a00400027a7a0809a6910800" ++
|
hex"0072006d006f007500720065006400200043006f00720070007300170040030050040003bc00000234040001a00400027a7a0809a6910800" ++
|
||||||
// hex"00000008090a6403603000001082202e040000000202378ae0e80c00000162710b82000000008083837032030000015e2583210000000020" ++
|
hex"00000008090a6403603000001082202e040000000202378ae0e80c00000162710b82000000008083837032030000015e2583210000000020" ++
|
||||||
// hex"20e21c0c80c000007722120e81c0000000808063483603000000"
|
hex"20e21c0c80c000007722120e81c0000000808063483603000000"
|
||||||
//
|
|
||||||
// "decode (Scrawny Ronnie's mosquito)" in {
|
"decode (Scrawny Ronnie's mosquito)" in {
|
||||||
// PacketCoding.DecodePacket(string_mosquito_seated).require match {
|
PacketCoding.DecodePacket(string_mosquito_seated).require match {
|
||||||
// case ObjectCreateMessage(len, cls, guid, parent, data) =>
|
case ObjectCreateMessage(len, cls, guid, parent, data) =>
|
||||||
// len mustEqual 1991
|
len mustEqual 1991
|
||||||
// cls mustEqual ObjectClass.mosquito
|
cls mustEqual ObjectClass.mosquito
|
||||||
// guid mustEqual PlanetSideGUID(4308)
|
guid mustEqual PlanetSideGUID(4308)
|
||||||
// parent mustEqual None
|
parent mustEqual None
|
||||||
// data match {
|
data match {
|
||||||
// case Some(vdata : VehicleData) =>
|
case Some(vdata : VehicleData) =>
|
||||||
// vdata.pos.coord mustEqual Vector3(4571.6875f, 5602.1875f, 93)
|
vdata.pos.coord mustEqual Vector3(4571.6875f, 5602.1875f, 93)
|
||||||
// vdata.pos.orient mustEqual Vector3(11.25f, 2.8125f, 92.8125f)
|
vdata.pos.orient mustEqual Vector3(11.25f, 2.8125f, 92.8125f)
|
||||||
// vdata.pos.vel mustEqual Some(Vector3(31.71875f, 8.875f, -0.03125f))
|
vdata.pos.vel mustEqual Some(Vector3(31.71875f, 8.875f, -0.03125f))
|
||||||
// vdata.faction mustEqual PlanetSideEmpire.TR
|
vdata.faction mustEqual PlanetSideEmpire.TR
|
||||||
// vdata.bops mustEqual false
|
vdata.bops mustEqual false
|
||||||
// vdata.destroyed mustEqual false
|
vdata.destroyed mustEqual false
|
||||||
// vdata.jammered mustEqual false
|
vdata.jammered mustEqual false
|
||||||
// vdata.owner_guid mustEqual PlanetSideGUID(3776)
|
vdata.owner_guid mustEqual PlanetSideGUID(3776)
|
||||||
// vdata.health mustEqual 255
|
vdata.health mustEqual 255
|
||||||
// vdata.no_mount_points mustEqual false
|
vdata.no_mount_points mustEqual false
|
||||||
// vdata.driveState mustEqual DriveState.Mobile
|
vdata.driveState mustEqual DriveState.Mobile
|
||||||
// vdata.cloak mustEqual false
|
vdata.cloak mustEqual false
|
||||||
// vdata.unk1 mustEqual 0
|
vdata.unk1 mustEqual 0
|
||||||
// vdata.unk2 mustEqual false
|
vdata.unk2 mustEqual false
|
||||||
// vdata.unk3 mustEqual false
|
vdata.unk3 mustEqual false
|
||||||
// vdata.unk4 mustEqual false
|
vdata.unk4 mustEqual false
|
||||||
// vdata.unk5 mustEqual false
|
vdata.unk5 mustEqual false
|
||||||
// vdata.unk6 mustEqual false
|
vdata.unk6 mustEqual false
|
||||||
// vdata.vehicle_format_data mustEqual Some(VariantVehicleData(7))
|
vdata.vehicle_format_data mustEqual Some(VariantVehicleData(7))
|
||||||
// vdata.inventory match {
|
vdata.inventory match {
|
||||||
// case Some(InventoryData(list)) =>
|
case Some(InventoryData(list)) =>
|
||||||
// list.head.objectClass mustEqual ObjectClass.avatar
|
list.head.objectClass mustEqual ObjectClass.avatar
|
||||||
// list.head.guid mustEqual PlanetSideGUID(3776)
|
list.head.guid mustEqual PlanetSideGUID(3776)
|
||||||
// list.head.parentSlot mustEqual 0
|
list.head.parentSlot mustEqual 0
|
||||||
// list.head.obj match {
|
list.head.obj match {
|
||||||
// case PlayerData(pos, app, char, Some(InventoryData(inv)), hand) =>
|
case PlayerData(None, app, char, Some(InventoryData(inv)), DrawnSlot.None) =>
|
||||||
// pos mustEqual None
|
app match {
|
||||||
// app.app.name mustEqual "ScrawnyRonnie"
|
case CharacterAppearanceData(a, b, ribbons) =>
|
||||||
// app.app.faction mustEqual PlanetSideEmpire.TR
|
a.app mustEqual BasicCharacterData("ScrawnyRonnie", PlanetSideEmpire.TR, CharacterGender.Male, 5, CharacterVoice.Voice5)
|
||||||
// app.app.sex mustEqual CharacterGender.Male
|
a.black_ops mustEqual false
|
||||||
// app.app.head mustEqual 5
|
a.jammered mustEqual false
|
||||||
// app.app.voice mustEqual CharacterVoice.Voice5
|
a.exosuit mustEqual ExoSuitType.Agile
|
||||||
// app.black_ops mustEqual false
|
a.unk1 mustEqual false
|
||||||
// app.lfs mustEqual false
|
a.unk2 mustEqual None
|
||||||
// app.outfit_name mustEqual "Black Beret Armoured Corps"
|
a.unk3 mustEqual None
|
||||||
// app.outfit_logo mustEqual 23
|
a.unk4 mustEqual 0
|
||||||
// app.facingPitch mustEqual 354.375f
|
a.unk5 mustEqual 0
|
||||||
// app.facingYawUpper mustEqual 0.0f
|
a.unk6 mustEqual 30777081L
|
||||||
// app.altModelBit mustEqual None
|
a.unk7 mustEqual 1
|
||||||
// app.charging_pose mustEqual false
|
a.unk8 mustEqual 4
|
||||||
// app.on_zipline mustEqual false
|
a.unk9 mustEqual 0
|
||||||
// app.backpack mustEqual false
|
a.unkA mustEqual 0
|
||||||
// app.ribbons.upper mustEqual MeritCommendation.MarkovVeteran
|
|
||||||
// app.ribbons.middle mustEqual MeritCommendation.HeavyInfantry4
|
b.outfit_name mustEqual "Black Beret Armoured Corps"
|
||||||
// app.ribbons.lower mustEqual MeritCommendation.TankBuster7
|
b.outfit_logo mustEqual 23
|
||||||
// app.ribbons.tos mustEqual MeritCommendation.SixYearTR
|
b.backpack mustEqual false
|
||||||
// char.health mustEqual 100
|
b.facingPitch mustEqual 348.75f
|
||||||
// char.armor mustEqual 0
|
b.facingYawUpper mustEqual 0
|
||||||
// char.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade
|
b.lfs mustEqual false
|
||||||
// char.command_rank mustEqual 5
|
b.grenade_state mustEqual GrenadeState.None
|
||||||
// char.implant_effects.isEmpty mustEqual true
|
b.is_cloaking mustEqual false
|
||||||
// char.cosmetics mustEqual Some(Cosmetics(true, true, true, true, false))
|
b.charging_pose mustEqual false
|
||||||
// inv.size mustEqual 4
|
b.on_zipline mustEqual None
|
||||||
// inv.head.objectClass mustEqual ObjectClass.medicalapplicator
|
b.unk0 mustEqual 316554L
|
||||||
// inv.head.parentSlot mustEqual 0
|
b.unk1 mustEqual false
|
||||||
// inv(1).objectClass mustEqual ObjectClass.bank
|
b.unk2 mustEqual false
|
||||||
// inv(1).parentSlot mustEqual 1
|
b.unk3 mustEqual false
|
||||||
// inv(2).objectClass mustEqual ObjectClass.mini_chaingun
|
b.unk4 mustEqual false
|
||||||
// inv(2).parentSlot mustEqual 2
|
b.unk5 mustEqual false
|
||||||
// inv(3).objectClass mustEqual ObjectClass.chainblade
|
b.unk6 mustEqual false
|
||||||
// inv(3).parentSlot mustEqual 4
|
b.unk7 mustEqual false
|
||||||
// hand mustEqual DrawnSlot.None
|
|
||||||
// case _ =>
|
case _ =>
|
||||||
// ko
|
ko
|
||||||
// }
|
}
|
||||||
// list(1).objectClass mustEqual ObjectClass.rotarychaingun_mosquito
|
|
||||||
// list(1).parentSlot mustEqual 1
|
char match {
|
||||||
// case None =>
|
case CharacterData(health, armor, uniform, unk, cr, implants, cosmetics) =>
|
||||||
// ko
|
health mustEqual 100
|
||||||
// }
|
armor mustEqual 0
|
||||||
// case _ =>
|
uniform mustEqual UniformStyle.ThirdUpgrade
|
||||||
// ko
|
unk mustEqual 7
|
||||||
// }
|
cr mustEqual 5
|
||||||
// case _ =>
|
implants mustEqual Nil
|
||||||
// ko
|
cosmetics mustEqual Some(Cosmetics(true, true, true, true, false))
|
||||||
// }
|
case _ =>
|
||||||
// }
|
ko
|
||||||
//
|
}
|
||||||
// "encode (Scrawny Ronnie's mosquito)" in {
|
//briefly ...
|
||||||
// val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData(
|
inv.size mustEqual 4
|
||||||
// BasicCharacterData("ScrawnyRonnie", PlanetSideEmpire.TR, CharacterGender.Male, 5, CharacterVoice.Voice5),
|
inv.head.objectClass mustEqual ObjectClass.medicalapplicator
|
||||||
// false, false,
|
inv.head.parentSlot mustEqual 0
|
||||||
// ExoSuitType.Agile,
|
inv(1).objectClass mustEqual ObjectClass.bank
|
||||||
// "Black Beret Armoured Corps",
|
inv(1).parentSlot mustEqual 1
|
||||||
// 23,
|
inv(2).objectClass mustEqual ObjectClass.mini_chaingun
|
||||||
// false,
|
inv(2).parentSlot mustEqual 2
|
||||||
// 354.375f, 0.0f,
|
inv(3).objectClass mustEqual ObjectClass.chainblade
|
||||||
// false,
|
inv(3).parentSlot mustEqual 4
|
||||||
// GrenadeState.None, false, false, None,
|
case _ =>
|
||||||
// RibbonBars(
|
ko
|
||||||
// MeritCommendation.MarkovVeteran,
|
}
|
||||||
// MeritCommendation.HeavyInfantry4,
|
//back to mosquito inventory
|
||||||
// MeritCommendation.TankBuster7,
|
list(1).objectClass mustEqual ObjectClass.rotarychaingun_mosquito
|
||||||
// MeritCommendation.SixYearTR
|
list(1).parentSlot mustEqual 1
|
||||||
// )
|
case None =>
|
||||||
// )
|
ko
|
||||||
// val char : (Boolean,Boolean)=>CharacterData = CharacterData(
|
}
|
||||||
// 100, 0,
|
case _ =>
|
||||||
// UniformStyle.ThirdUpgrade,
|
ko
|
||||||
// 0,
|
}
|
||||||
// 5,
|
case _ =>
|
||||||
// Nil,
|
ko
|
||||||
// Some(Cosmetics(true, true, true, true, false))
|
}
|
||||||
// )
|
}
|
||||||
// val inv : InventoryData = InventoryData(
|
|
||||||
// List(
|
"encode (Scrawny Ronnie's mosquito)" in {
|
||||||
// InternalSlot(ObjectClass.medicalapplicator, PlanetSideGUID(4201), 0,
|
val a : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
||||||
// WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.health_canister, PlanetSideGUID(3472), 0, AmmoBoxData(0))))
|
BasicCharacterData(
|
||||||
// ),
|
"ScrawnyRonnie",
|
||||||
// InternalSlot(ObjectClass.bank, PlanetSideGUID(2952), 1,
|
PlanetSideEmpire.TR,
|
||||||
// WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.armor_canister, PlanetSideGUID(3758), 0, AmmoBoxData(0))))
|
CharacterGender.Male,
|
||||||
// ),
|
5,
|
||||||
// InternalSlot(ObjectClass.mini_chaingun, PlanetSideGUID(2929), 2,
|
CharacterVoice.Voice5
|
||||||
// WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.bullet_9mm, PlanetSideGUID(3292), 0, AmmoBoxData(0))))
|
),
|
||||||
// ),
|
false,
|
||||||
// InternalSlot(ObjectClass.chainblade, PlanetSideGUID(3222), 4,
|
false,
|
||||||
// WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.melee_ammo, PlanetSideGUID(3100), 0, AmmoBoxData(0))))
|
false,
|
||||||
// )
|
None,
|
||||||
// )
|
false,
|
||||||
// )
|
ExoSuitType.Agile,
|
||||||
// val player = VehicleData.PlayerData(app, char, inv, DrawnSlot.None, VehicleData.InitialStreamLengthToSeatEntries(true, VehicleFormat.Variant))
|
None,
|
||||||
// val obj = VehicleData(
|
0,
|
||||||
// PlacementData(
|
0,
|
||||||
// Vector3(4571.6875f, 5602.1875f, 93),
|
30777081L,
|
||||||
// Vector3(11.25f, 2.8125f, 92.8125f),
|
1,
|
||||||
// Some(Vector3(31.71875f, 8.875f, -0.03125f))
|
4,
|
||||||
// ),
|
0,
|
||||||
// PlanetSideEmpire.TR,
|
0
|
||||||
// false, false,
|
)
|
||||||
// 0,
|
val b : (Boolean,Int)=>CharacterAppearanceB = CharacterAppearanceB(
|
||||||
// false, false,
|
316554L,
|
||||||
// PlanetSideGUID(3776),
|
"Black Beret Armoured Corps",
|
||||||
// false,
|
23,
|
||||||
// 255,
|
false,
|
||||||
// false, false,
|
false,
|
||||||
// DriveState.Mobile,
|
false,
|
||||||
// false, false, false,
|
false,
|
||||||
// Some(VariantVehicleData(7)),
|
false,
|
||||||
// Some(
|
348.75f, 0,
|
||||||
// InventoryData(
|
false,
|
||||||
// List(
|
GrenadeState.None,
|
||||||
// InternalSlot(ObjectClass.avatar, PlanetSideGUID(3776), 0, player),
|
false,
|
||||||
// InternalSlot(ObjectClass.rotarychaingun_mosquito, PlanetSideGUID(3602), 1,
|
false,
|
||||||
// WeaponData(6, 0, 0, List(InternalSlot(ObjectClass.bullet_12mm, PlanetSideGUID(3538), 0, AmmoBoxData(0))))
|
false,
|
||||||
// )
|
false,
|
||||||
// )
|
false,
|
||||||
// )
|
None
|
||||||
// )
|
)
|
||||||
// )(VehicleFormat.Variant)
|
|
||||||
// val msg = ObjectCreateMessage(ObjectClass.mosquito, PlanetSideGUID(4308), obj)
|
val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData(
|
||||||
// val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
a, b,
|
||||||
//
|
RibbonBars(
|
||||||
// val pkt_bitv = pkt.toBitVector
|
MeritCommendation.MarkovVeteran,
|
||||||
// val ori_bitv = string_mosquito_seated.toBitVector
|
MeritCommendation.HeavyInfantry4,
|
||||||
// pkt_bitv.take(555) mustEqual ori_bitv.take(555) //skip 126
|
MeritCommendation.TankBuster7,
|
||||||
// pkt_bitv.drop(681).take(512) mustEqual ori_bitv.drop(681).take(512) //renew
|
MeritCommendation.SixYearTR
|
||||||
// pkt_bitv.drop(1193).take(88) mustEqual ori_bitv.drop(1193).take(88) //skip 3
|
)
|
||||||
// pkt_bitv.drop(1284).take(512) mustEqual ori_bitv.drop(1284).take(512) //renew
|
)
|
||||||
// pkt_bitv.drop(1796) mustEqual ori_bitv.drop(1796)
|
val char : (Boolean,Boolean)=>CharacterData = CharacterData(
|
||||||
// //TODO work on CharacterData to make this pass as a single stream
|
100, 0,
|
||||||
// }
|
UniformStyle.ThirdUpgrade,
|
||||||
|
7,
|
||||||
|
5,
|
||||||
|
Nil,
|
||||||
|
Some(Cosmetics(true, true, true, true, false))
|
||||||
|
)
|
||||||
|
val inv : InventoryData = InventoryData(
|
||||||
|
List(
|
||||||
|
InternalSlot(ObjectClass.medicalapplicator, PlanetSideGUID(4201), 0,
|
||||||
|
WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.health_canister, PlanetSideGUID(3472), 0, AmmoBoxData(0))))
|
||||||
|
),
|
||||||
|
InternalSlot(ObjectClass.bank, PlanetSideGUID(2952), 1,
|
||||||
|
WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.armor_canister, PlanetSideGUID(3758), 0, AmmoBoxData(0))))
|
||||||
|
),
|
||||||
|
InternalSlot(ObjectClass.mini_chaingun, PlanetSideGUID(2929), 2,
|
||||||
|
WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.bullet_9mm, PlanetSideGUID(3292), 0, AmmoBoxData(0))))
|
||||||
|
),
|
||||||
|
InternalSlot(ObjectClass.chainblade, PlanetSideGUID(3222), 4,
|
||||||
|
WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.melee_ammo, PlanetSideGUID(3100), 0, AmmoBoxData(0))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val player = VehicleData.PlayerData(app, char, inv, DrawnSlot.None, VehicleData.InitialStreamLengthToSeatEntries(true, VehicleFormat.Variant))
|
||||||
|
val obj = VehicleData(
|
||||||
|
PlacementData(
|
||||||
|
Vector3(4571.6875f, 5602.1875f, 93),
|
||||||
|
Vector3(11.25f, 2.8125f, 92.8125f),
|
||||||
|
Some(Vector3(31.71875f, 8.875f, -0.03125f))
|
||||||
|
),
|
||||||
|
PlanetSideEmpire.TR,
|
||||||
|
false, false,
|
||||||
|
0,
|
||||||
|
false, false,
|
||||||
|
PlanetSideGUID(3776),
|
||||||
|
false,
|
||||||
|
255,
|
||||||
|
false, false,
|
||||||
|
DriveState.Mobile,
|
||||||
|
false, false, false,
|
||||||
|
Some(VariantVehicleData(7)),
|
||||||
|
Some(
|
||||||
|
InventoryData(
|
||||||
|
List(
|
||||||
|
InternalSlot(ObjectClass.avatar, PlanetSideGUID(3776), 0, player),
|
||||||
|
InternalSlot(ObjectClass.rotarychaingun_mosquito, PlanetSideGUID(3602), 1,
|
||||||
|
WeaponData(6, 0, 0, List(InternalSlot(ObjectClass.bullet_12mm, PlanetSideGUID(3538), 0, AmmoBoxData(0))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)(VehicleFormat.Variant)
|
||||||
|
val msg = ObjectCreateMessage(ObjectClass.mosquito, PlanetSideGUID(4308), obj)
|
||||||
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
pkt mustEqual string_mosquito_seated
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -484,7 +484,7 @@ class PacketCodingActorITest extends ActorTest {
|
||||||
)
|
)
|
||||||
val obj = DetailedPlayerData(pos, app, char, InventoryData(Nil), DrawnSlot.None)
|
val obj = DetailedPlayerData(pos, app, char, InventoryData(Nil), DrawnSlot.None)
|
||||||
val pkt = MultiPacketBundle(List(ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj)))
|
val pkt = MultiPacketBundle(List(ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj)))
|
||||||
val string_hex = hex"000900001879060000bc84b000000000000000000002040000097049006c006c006c004900490049006c006c006c0049006c0049006c006c0049006c006c006c0049006c006c0049008452700000000000000000000000000000002000000fe6a703fffffffffffffffffffffffffffffffc00000000000000000000000000000000000000019001900064000001007ec800c80000000000000000000000000000000000000001c00042c54686c7000000000000000000000000000000000000000000000000000000000000000000000000200700"
|
val string_hex = hex"000900001879060000bc84b000000000000000000002040000097049006c006c006c004900490049006c006c006c0049006c0049006c006c0049006c006c006c0049006c006c00490084524000000000000000000000000000000020000007f35703fffffffffffffffffffffffffffffffc000000000000000000000000000000000000000190019000640000000000c800c80000000000000000000000000000000000000001c00042c54686c7000000000000000000000000000000000000000000000000000000000000000000000400e0"
|
||||||
|
|
||||||
"PacketCodingActor" should {
|
"PacketCodingActor" should {
|
||||||
"bundle an r-originating packet into an l-facing SlottedMetaPacket byte stream data (SlottedMetaPacket)" in {
|
"bundle an r-originating packet into an l-facing SlottedMetaPacket byte stream data (SlottedMetaPacket)" in {
|
||||||
|
|
@ -545,34 +545,92 @@ class PacketCodingActorJTest extends ActorTest {
|
||||||
class PacketCodingActorKTest extends ActorTest {
|
class PacketCodingActorKTest extends ActorTest {
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
val pos : PlacementData = PlacementData(Vector3.Zero, Vector3.Zero)
|
val pos : PlacementData = PlacementData(Vector3.Zero, Vector3.Zero)
|
||||||
val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData(
|
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
||||||
BasicCharacterData("IlllIIIlllIlIllIlllIllI", PlanetSideEmpire.VS, CharacterGender.Female, 41, CharacterVoice.Voice1),
|
BasicCharacterData(
|
||||||
|
"IlllIIIlllIlIllIlllIllI",
|
||||||
|
PlanetSideEmpire.VS,
|
||||||
|
CharacterGender.Female,
|
||||||
|
41,
|
||||||
|
CharacterVoice.Voice1
|
||||||
|
),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
ExoSuitType.Standard,
|
ExoSuitType.Standard,
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
41605313L,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
65535
|
||||||
|
)
|
||||||
|
val ab : (Boolean,Int)=>CharacterAppearanceB = CharacterAppearanceB(
|
||||||
|
0L,
|
||||||
"",
|
"",
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
2.8125f, 210.9375f,
|
2.8125f, 210.9375f,
|
||||||
true,
|
false,
|
||||||
GrenadeState.None,
|
GrenadeState.None,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
None,
|
false,
|
||||||
RibbonBars()
|
false,
|
||||||
)
|
false,
|
||||||
var char : (Option[Int])=>DetailedCharacterData = DetailedCharacterData(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
100, 100,
|
|
||||||
50,
|
|
||||||
100, 100,
|
|
||||||
List(CertificationType.StandardAssault, CertificationType.MediumAssault, CertificationType.ATV, CertificationType.Harasser, CertificationType.StandardExoSuit, CertificationType.AgileExoSuit, CertificationType.ReinforcedExoSuit),
|
|
||||||
List(),
|
|
||||||
List("xpe_sanctuary_help", "xpe_th_firemodes", "used_beamer", "map13"),
|
|
||||||
List.empty,
|
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData(
|
||||||
|
aa, ab,
|
||||||
|
RibbonBars()
|
||||||
|
)
|
||||||
|
val ba : DetailedCharacterA = DetailedCharacterA(
|
||||||
|
0L,
|
||||||
|
0L,
|
||||||
|
0L, 0L, 0L,
|
||||||
|
100, 100,
|
||||||
|
false,
|
||||||
|
50,
|
||||||
|
32831L,
|
||||||
|
100, 100,
|
||||||
|
0, 0, 0L,
|
||||||
|
List(0, 0, 0, 0, 0, 0),
|
||||||
|
List(
|
||||||
|
CertificationType.StandardAssault,
|
||||||
|
CertificationType.MediumAssault,
|
||||||
|
CertificationType.ATV,
|
||||||
|
CertificationType.Harasser,
|
||||||
|
CertificationType.StandardExoSuit,
|
||||||
|
CertificationType.AgileExoSuit,
|
||||||
|
CertificationType.ReinforcedExoSuit
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val bb : (Long, Option[Int])=>DetailedCharacterB = DetailedCharacterB(
|
||||||
|
None,
|
||||||
|
Nil,
|
||||||
|
Nil, Nil,
|
||||||
|
List(
|
||||||
|
"xpe_sanctuary_help",
|
||||||
|
"xpe_th_firemodes",
|
||||||
|
"used_beamer",
|
||||||
|
"map13"
|
||||||
|
),
|
||||||
|
Nil,
|
||||||
|
0L, 0L, 0L, 0L, 0L,
|
||||||
|
Some(DCDExtra2(0, 0)),
|
||||||
|
Nil, Nil, false,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
val char : (Option[Int])=>DetailedCharacterData =
|
||||||
|
(pad_length : Option[Int]) => DetailedCharacterData(ba, bb(ba.bep, pad_length))(pad_length)
|
||||||
val obj = DetailedPlayerData(pos, app, char, InventoryData(Nil), DrawnSlot.None)
|
val obj = DetailedPlayerData(pos, app, char, InventoryData(Nil), DrawnSlot.None)
|
||||||
val list = List(
|
val list = List(
|
||||||
ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj),
|
ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue