mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-03-13 01:10:36 +00:00
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:
parent
caf56c4e72
commit
292a9bad23
7 changed files with 422 additions and 418 deletions
|
|
@ -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] = {
|
||||
|
|
|
|||
|
|
@ -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) ::
|
||||
|
|
|
|||
|
|
@ -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))) ::
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 _ => ;
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue