attached version of the OCM for avatars works; known encoding issues with OCDM encoding for avatars, specifically the calculated bit length

This commit is contained in:
FateJH 2018-06-03 21:35:58 -04:00
parent caf56c4e72
commit 292a9bad23
7 changed files with 422 additions and 418 deletions

View file

@ -13,15 +13,27 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
override def ConstructorData(obj : Player) : Try[PlayerData] = {
import AvatarConverter._
val MaxArmor = obj.MaxArmor
Success(
PlayerData.apply(
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
MakeAppearanceData(obj),
MakeCharacterData(obj),
MakeInventoryData(obj),
GetDrawnSlot(obj)
if(obj.VehicleSeated.isEmpty) {
Success(
PlayerData(
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
MakeAppearanceData(obj),
MakeCharacterData(obj),
MakeInventoryData(obj),
GetDrawnSlot(obj)
)
)
)
}
else {
Success(
PlayerData(
MakeAppearanceData(obj),
MakeCharacterData(obj),
MakeInventoryData(obj),
GetDrawnSlot(obj)
)
)
}
}
override def DetailedConstructorData(obj : Player) : Try[DetailedPlayerData] = {

View file

@ -55,12 +55,12 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
* @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)
val appearance = basic_appearance(5)
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)
val appearance = basic_appearance(5)
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), None, drawn_slot)(false)
}
/**
@ -71,18 +71,18 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
* @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)))
val appearance = basic_appearance(PlayerData.PaddingOffset(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)))
val appearance = basic_appearance(PlayerData.PaddingOffset(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 =>
("basic_appearance" | CharacterAppearanceData.codec(PlayerData.PaddingOffset(pos))) >>:~ { app =>
("character_data" | DetailedCharacterData.codec(app.altModelBit)) ::
optional(bool, "inventory" | InventoryData.codec_detailed) ::
("drawn_slot" | DrawnSlot.codec) ::

View file

@ -60,12 +60,10 @@ object PlayerData extends Marshallable[PlayerData] {
* @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
* @param accumulative the input position for the stream up to which this entry;
* used to calculate the padding value for the player's name in `CharacterAppearanceData`
* @return a `PlayerData` object
*/
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type, accumulative : Long) : PlayerData = {
val appearance = basic_appearance(1)
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type) : PlayerData = {
val appearance = basic_appearance(5)
PlayerData(None, appearance, character_data(appearance.backpack, true), Some(inventory), drawn_slot)(false)
}
/**
@ -75,12 +73,10 @@ object PlayerData extends Marshallable[PlayerData] {
* @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 drawn_slot the holster that is initially drawn
* @param accumulative the input position for the stream up to which this entry;
* used to calculate the padding value for the player's name in `CharacterAppearanceData`
* @return a `PlayerData` object
*/
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, drawn_slot : DrawnSlot.Type, accumulative : Long) : PlayerData = {
val appearance = basic_appearance(1)
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, drawn_slot : DrawnSlot.Type) : PlayerData = {
val appearance = basic_appearance(5)
PlayerData(None, appearance, character_data(appearance.backpack, true), None, drawn_slot)(false)
}
@ -96,7 +92,7 @@ object PlayerData extends Marshallable[PlayerData] {
* @return a `PlayerData` object
*/
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type) : PlayerData = {
val appearance = basic_appearance( placementOffset(Some(pos)) )
val appearance = basic_appearance( PaddingOffset(Some(pos)) )
PlayerData(Some(pos), appearance, character_data(appearance.backpack, false), Some(inventory), drawn_slot)(true)
}
/**
@ -110,26 +106,52 @@ object PlayerData extends Marshallable[PlayerData] {
* @return a `PlayerData` object
*/
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, drawn_slot : DrawnSlot.Type) : PlayerData = {
val appearance = basic_appearance( placementOffset(Some(pos)) )
val appearance = basic_appearance( PaddingOffset(Some(pos)) )
PlayerData(Some(pos), appearance, character_data(appearance.backpack, false), None, drawn_slot)(true)
}
/**
* Determine the padding offset for a subsequent field given the existence of `PlacementData`.
* With the `PlacementData` objects, a question of the optional velocity field also exists.<br>
* <br>
* With just `PlacementData`, the bit distance to the name field is 164 (padding: 4 bits).
* With `PlacementData` with velocity, the bit distance to the name field is 206 (padding: 2 bits).
* Without `PlacementData`, the distance to the name field is either 107 or 115 (padding: 5 bits).
* The padding will always be a number 0-7.
* @see `PlacementData`
* @param pos the optional `PlacementData` object that creates the shift in bits
* @return the pad length in bits
*/
def placementOffset(pos : Option[PlacementData]) : Int = {
def PaddingOffset(pos : Option[PlacementData]) : Int = {
/*
The `ObjectCreateMessage` length is either 32 + 12 + 16 + 81 - 141 - with `PlacementData`,
with an additional +42 - 183 - with the optional velocity field,
or 32 + 12 + 16 + 16 + 8/16 - 84/92 - without any `PlacementData`.
23 is the distance of all the fields before the player's `name` field in `CharacterAppearanceData`.
*/
pos match {
case Some(place) =>
if(place.vel.isDefined) { 2 } else { 4 }
case None =>
1
5 //with ObjectCreateMessageParent data
}
}
/**
* Find the number of trailing bits that need to be added to make the current value perfectly divisible by eight.
* @param length the current length of a stream
* @return the number of bits needed to pad it
*/
def ByteAlignmentPadding(length : Long) : Int = {
val pad = (length - math.floor(length / 8) * 8).toInt
if(pad > 0) {
8 - pad
}
else {
0
}
}
/**
* This `Codec` is generic.
* However, it should not be used to translate a `Player` object
@ -140,7 +162,7 @@ object PlayerData extends Marshallable[PlayerData] {
*/
def codec(position_defined : Boolean) : Codec[PlayerData] = (
conditional(position_defined, "pos" | PlacementData.codec) >>:~ { pos =>
("basic_appearance" | CharacterAppearanceData.codec(placementOffset(pos))) >>:~ { app =>
("basic_appearance" | CharacterAppearanceData.codec(PaddingOffset(pos))) >>:~ { app =>
("character_data" | newcodecs.binary_choice(position_defined,
CharacterData.codec(app.backpack),
CharacterData.codec_seated(app.backpack))) ::

View file

@ -329,14 +329,7 @@ object VehicleData extends Marshallable[VehicleData] {
* @return the padding value, 0-7 bits
*/
private def CumulativeSeatedPlayerNamePadding(accumulative : Long) : Int = {
val offset = accumulative + 23 + 35
val pad = ((offset - math.floor(offset / 8) * 8) % 8).toInt
if(pad > 0) {
8 - pad
}
else {
0
}
Player_Data.ByteAlignmentPadding(accumulative + 23 + 35)
}
/**

View file

@ -12,10 +12,10 @@ class CharacterDataTest extends Specification {
val string = hex"17 73070000 BC8 3E0F 6C2D7 65535 CA16 00 00 09 9741E4F804000000 234530063007200610077006E00790052006F006E006E0069006500 220B7 E67B540404001000000000022B50100 268042006C00610063006B002000420065007200650074002000410072006D006F007500720065006400200043006F00720070007300 1700E0030050040003BC00000234040001A004000 3FFF67A8F A0A5424E0E800000000080952A9C3A03000001081103E040000000A023782F1080C0000016244108200000000808382403A030000014284C3A0C0000000202512F00B80C00000578F80F840000000280838B3C320300000080"
//string seated was intentionally-produced test data
val string_seated =
hex"17ff06000069023c83e0f800000011a530063007200610077006e00790052006f006e006e0069006500220b7000000000000000000000000" ++
hex"6800000268042006c00610063006b002000420065007200650074002000410072006d006f007500720065006400200043006f00720070007" ++
hex"3001700e0030050040003bc00000234040001a00400020a8fa0a5424e0e800000000080952a9c3a03000001081103e040000000a023782f1" ++
hex"080c0000016244108200000000808382403a030000014284c3a0c0000000202512f00b80c00000578f80f840000000280838b3c32030000008"
hex"170307000069023c83e0f800000011a0530063007200610077006e00790052006f006e006e0069006500220b700000000000000000000000" ++
hex"06800000268042006c00610063006b002000420065007200650074002000410072006d006f007500720065006400200043006f0072007000" ++
hex"73001700e0030050040003bc00000234040001a00400020a8fa0a5424e0e800000000080952a9c3a03000001081103e040000000a023782f" ++
hex"1080c0000016244108200000000808382403a030000014284c3a0c0000000202512f00b80c00000578f80f840000000280838b3c320300000080"
val string_backpack = hex"17 9C030000 BC8 340D F20A9 3956C AF0D 00 00 73 480000 87041006E00670065006C006C006F00 4A148 0000000000000000000000005C54200 24404F0072006900670069006E0061006C00200044006900730074007200690063007400 1740180181E8000000C202000042000000D202000000010A3C00"
"CharacterData" should {
@ -120,7 +120,7 @@ class CharacterDataTest extends Specification {
"decode (seated)" in {
PacketCoding.DecodePacket(string_seated).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 1791
len mustEqual 1795
cls mustEqual ObjectClass.avatar
guid mustEqual PlanetSideGUID(3902)
parent mustEqual Some(ObjectCreateMessageParent(PlanetSideGUID(1234), 0))
@ -276,11 +276,6 @@ class CharacterDataTest extends Specification {
}
"encode (seated)" in {
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",
@ -322,7 +317,7 @@ class CharacterDataTest extends Specification {
InventoryItemData(ObjectClass.chainblade, PlanetSideGUID(4088), 4, WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, AmmoBoxData())) ::
Nil
)
val obj = PlayerData(app, char, inv, DrawnSlot.Rifle1, 0)
val obj = PlayerData(app, char, inv, DrawnSlot.Rifle1)
val msg = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(3902), ObjectCreateMessageParent(PlanetSideGUID(1234), 0), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector

File diff suppressed because one or more lines are too long

View file

@ -1661,7 +1661,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
continent.Corpses.foreach {
TurnPlayerIntoCorpse
}
var mountedPlayers : Set[Player] = Set.empty //players in vehicles
//load active vehicles in zone
continent.Vehicles.foreach(vehicle => {
val definition = vehicle.Definition
@ -1685,7 +1684,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
case _ => ;
}
//seat terminal occupants
import net.psforever.objects.definition.converter.AvatarConverter
continent.GUID(terminal_guid) match {
case Some(obj : Mountable) =>
obj.Seats
@ -1697,25 +1695,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
tdefintion.ObjectId,
tplayer.GUID,
ObjectCreateMessageParent(parent_guid, index),
PlayerData(
AvatarConverter.MakeAppearanceData(tplayer),
AvatarConverter.MakeCharacterData(tplayer),
AvatarConverter.MakeInventoryData(tplayer),
AvatarConverter.GetDrawnSlot(tplayer),
0
)
tdefintion.Packet.ConstructorData(tplayer).get
))
})
obj.MountPoints.foreach({ case ((_, seat_num)) =>
obj.Seat(seat_num).get.Occupant match {
case Some(tplayer) =>
if(tplayer.HasGUID) {
sendResponse(ObjectAttachMessage(parent_guid, tplayer.GUID, seat_num))
}
case None => ;
}
})
case _ => ;
}
})