mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-03-02 03:33:40 +00:00
* Add .scalafmt.conf
* Adopt quill for database access
* Removed postgresql-async
* Refactored all instances of database access
* Creating duplicate characters of the same account is no longer possible
* Rewrote large parts of LoginSessionActor
* Implement migrations
* Move overrides into subdirectory
* Make usernames case insensitive
* Use LOWER(?) comparison instead of storing lowercased username
* import scala.util.{Success, Failure}
* Add config and joda-time dependencies
* Add sbt-scalafmt
* Use defaultWithAlign scalafmt preset
* Format all
* Add scalafix
* Remove unused imports
* Don't lowercase username when inserting
* Update readme
* Listen on worldserver.Hostname address
* Remove database test on startup
It could fail when the global thread pool is busy loading zone
maps. Migrations run on the main thread and also serve the
purpose of verifying the database configuration so it's fine to
remove the test altogether.
* Refactor chat message handlers, zones
What started as a small change to how zones are stored turned
into a pretty big effort of refactoring the chat message handler.
The !hack command was removed, the /capturebase commandwas added.
* Expose db ports in docker-compose.yml
* Silence property override log
* Rework configuration
* Unify configuration using the typesafe.config library
* Add configuration option for public address
* Configuration is now loaded from application.conf rather than worldserver.ini
* Refactor PsLogin and remove unnecessary logging
* Move pslogin into net.psforever.pslogin namespace
* Fix coverage
615 lines
22 KiB
Scala
615 lines
22 KiB
Scala
// Copyright (c) 2017 PSForever
|
|
package game.objectcreate
|
|
|
|
import net.psforever.packet.PacketCoding
|
|
import net.psforever.packet.game.ObjectCreateMessage
|
|
import net.psforever.packet.game.objectcreate._
|
|
import net.psforever.types._
|
|
import org.specs2.mutable._
|
|
import scodec.bits._
|
|
|
|
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"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 {
|
|
"decode" in {
|
|
PacketCoding.DecodePacket(string).require match {
|
|
case ObjectCreateMessage(len, cls, guid, parent, data) =>
|
|
len mustEqual 1907
|
|
cls mustEqual ObjectClass.avatar
|
|
guid mustEqual PlanetSideGUID(3902)
|
|
parent.isDefined mustEqual false
|
|
data match {
|
|
case PlayerData(Some(pos), basic, char, inv, hand) =>
|
|
pos.coord mustEqual Vector3(3674.8438f, 2726.789f, 91.15625f)
|
|
pos.orient mustEqual Vector3(0f, 0f, 64.6875f)
|
|
pos.vel.isDefined mustEqual true
|
|
pos.vel.get mustEqual Vector3(1.4375f, -0.4375f, 0f)
|
|
|
|
basic match {
|
|
case CharacterAppearanceData(a, b, ribbons) =>
|
|
a.app.name mustEqual "ScrawnyRonnie"
|
|
a.app.faction mustEqual PlanetSideEmpire.TR
|
|
a.app.sex mustEqual CharacterGender.Male
|
|
a.app.head mustEqual 5
|
|
a.app.voice mustEqual CharacterVoice.Voice5
|
|
a.data.bops mustEqual false
|
|
a.data.v1 mustEqual false
|
|
a.data.v2.isEmpty mustEqual true
|
|
a.data.jammered mustEqual false
|
|
a.data.v4.isEmpty mustEqual true
|
|
a.data.v5.isEmpty mustEqual true
|
|
a.exosuit mustEqual ExoSuitType.Reinforced
|
|
a.unk5 mustEqual 0
|
|
a.char_id mustEqual 30777081L
|
|
a.unk7 mustEqual 1
|
|
a.unk8 mustEqual 4
|
|
a.unk9 mustEqual 0
|
|
a.unkA mustEqual 0
|
|
|
|
b.outfit_name mustEqual "Black Beret Armoured Corps"
|
|
b.outfit_logo mustEqual 23
|
|
b.backpack mustEqual false
|
|
b.facingPitch mustEqual -39.375f
|
|
b.facingYawUpper mustEqual 0
|
|
b.lfs mustEqual false
|
|
b.grenade_state mustEqual GrenadeState.None
|
|
b.is_cloaking mustEqual false
|
|
b.charging_pose mustEqual false
|
|
b.on_zipline.isEmpty mustEqual true
|
|
b.unk0 mustEqual 316554L
|
|
b.unk1 mustEqual false
|
|
b.unk2 mustEqual false
|
|
b.unk3 mustEqual false
|
|
b.unk4 mustEqual false
|
|
b.unk5 mustEqual false
|
|
b.unk6 mustEqual false
|
|
b.unk7 mustEqual false
|
|
|
|
ribbons.upper mustEqual MeritCommendation.MarkovVeteran
|
|
ribbons.middle mustEqual MeritCommendation.HeavyInfantry4
|
|
ribbons.lower mustEqual MeritCommendation.TankBuster7
|
|
ribbons.tos mustEqual MeritCommendation.SixYearTR
|
|
case _ =>
|
|
ko
|
|
}
|
|
|
|
char.health mustEqual 255
|
|
char.armor mustEqual 253
|
|
char.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade
|
|
char.command_rank mustEqual 5
|
|
char.implant_effects.length mustEqual 1
|
|
char.implant_effects.head mustEqual ImplantEffects.NoEffects
|
|
char.cosmetics match {
|
|
case Some(c: Cosmetics) =>
|
|
c.Styles mustEqual Set(
|
|
PersonalStyle.NoHelmet,
|
|
PersonalStyle.Beret,
|
|
PersonalStyle.Sunglasses,
|
|
PersonalStyle.Earpiece
|
|
)
|
|
case None =>
|
|
ko
|
|
}
|
|
char.unk mustEqual 7
|
|
//short test of inventory items
|
|
inv.isDefined mustEqual true
|
|
val contents = inv.get.contents
|
|
contents.size mustEqual 5
|
|
//0
|
|
contents.head.objectClass mustEqual ObjectClass.plasma_grenade
|
|
contents.head.guid mustEqual PlanetSideGUID(3662)
|
|
contents.head.parentSlot mustEqual 0
|
|
contents.head.obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
|
|
contents.head.obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.plasma_grenade_ammo
|
|
contents.head.obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3751)
|
|
//1
|
|
contents(1).objectClass mustEqual ObjectClass.bank
|
|
contents(1).guid mustEqual PlanetSideGUID(3908)
|
|
contents(1).parentSlot mustEqual 1
|
|
contents(1).obj.asInstanceOf[WeaponData].fire_mode mustEqual 1
|
|
contents(1).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.armor_canister
|
|
contents(1).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(4143)
|
|
//2
|
|
contents(2).objectClass mustEqual ObjectClass.mini_chaingun
|
|
contents(2).guid mustEqual PlanetSideGUID(4164)
|
|
contents(2).parentSlot mustEqual 2
|
|
contents(2).obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
|
|
contents(2).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.bullet_9mm
|
|
contents(2).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3728)
|
|
//3
|
|
contents(3).objectClass mustEqual ObjectClass.phoenix //actually, a decimator
|
|
contents(3).guid mustEqual PlanetSideGUID(3603)
|
|
contents(3).parentSlot mustEqual 3
|
|
contents(3).obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
|
|
contents(3).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.phoenix_missile
|
|
contents(3).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3056)
|
|
//4
|
|
contents(4).objectClass mustEqual ObjectClass.chainblade
|
|
contents(4).guid mustEqual PlanetSideGUID(4088)
|
|
contents(4).parentSlot mustEqual 4
|
|
contents(4).obj.asInstanceOf[WeaponData].fire_mode mustEqual 1
|
|
contents(4).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.melee_ammo
|
|
contents(4).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3279)
|
|
|
|
hand mustEqual DrawnSlot.Rifle1
|
|
case _ =>
|
|
ko
|
|
}
|
|
case _ =>
|
|
ko
|
|
}
|
|
}
|
|
//
|
|
"decode (seated)" in {
|
|
PacketCoding.DecodePacket(string_seated).require match {
|
|
case ObjectCreateMessage(len, cls, guid, parent, data) =>
|
|
len mustEqual 1795
|
|
cls mustEqual ObjectClass.avatar
|
|
guid mustEqual PlanetSideGUID(3902)
|
|
parent.contains(ObjectCreateMessageParent(PlanetSideGUID(1234), 0)) mustEqual true
|
|
data match {
|
|
case PlayerData(None, basic, _, _, _) =>
|
|
basic match {
|
|
case CharacterAppearanceData(a, b, ribbons) =>
|
|
a.app.name mustEqual "ScrawnyRonnie"
|
|
a.app.faction mustEqual PlanetSideEmpire.TR
|
|
a.app.sex mustEqual CharacterGender.Male
|
|
a.app.head mustEqual 5
|
|
a.app.voice mustEqual CharacterVoice.Voice5
|
|
a.data.bops mustEqual false
|
|
a.data.v1 mustEqual false
|
|
a.data.v2.isEmpty mustEqual true
|
|
a.data.jammered mustEqual false
|
|
a.data.v4.isEmpty mustEqual true
|
|
a.data.v5.isEmpty mustEqual true
|
|
a.exosuit mustEqual ExoSuitType.Reinforced
|
|
a.unk5 mustEqual 0
|
|
a.char_id mustEqual 192L
|
|
a.unk7 mustEqual 0
|
|
a.unk8 mustEqual 0
|
|
a.unk9 mustEqual 0
|
|
a.unkA mustEqual 0
|
|
|
|
b.outfit_name mustEqual "Black Beret Armoured Corps"
|
|
b.outfit_logo mustEqual 23
|
|
b.backpack mustEqual false
|
|
b.facingPitch mustEqual -39.375f
|
|
b.facingYawUpper mustEqual 0
|
|
b.lfs mustEqual false
|
|
b.grenade_state mustEqual GrenadeState.None
|
|
b.is_cloaking mustEqual false
|
|
b.charging_pose mustEqual false
|
|
b.on_zipline.isEmpty mustEqual true
|
|
b.unk0 mustEqual 26L
|
|
b.unk1 mustEqual false
|
|
b.unk2 mustEqual false
|
|
b.unk3 mustEqual false
|
|
b.unk4 mustEqual false
|
|
b.unk5 mustEqual false
|
|
b.unk6 mustEqual false
|
|
b.unk7 mustEqual false
|
|
|
|
ribbons.upper mustEqual MeritCommendation.MarkovVeteran
|
|
ribbons.middle mustEqual MeritCommendation.HeavyInfantry4
|
|
ribbons.lower mustEqual MeritCommendation.TankBuster7
|
|
ribbons.tos mustEqual MeritCommendation.SixYearTR
|
|
//etc..
|
|
case _ =>
|
|
ko
|
|
}
|
|
case _ =>
|
|
ko
|
|
}
|
|
case _ =>
|
|
ko
|
|
}
|
|
}
|
|
|
|
"decode (backpack)" in {
|
|
PacketCoding.DecodePacket(string_backpack).require match {
|
|
case ObjectCreateMessage(len, cls, guid, parent, data) =>
|
|
len mustEqual 924L
|
|
cls mustEqual ObjectClass.avatar
|
|
guid mustEqual PlanetSideGUID(3380)
|
|
parent.isDefined mustEqual false
|
|
data match {
|
|
case PlayerData(Some(pos), basic, char, None, hand) =>
|
|
pos.coord mustEqual Vector3(4629.8906f, 6316.4453f, 54.734375f)
|
|
pos.orient mustEqual Vector3(0, 0, 126.5625f)
|
|
pos.vel.isDefined mustEqual false
|
|
|
|
basic match {
|
|
case CharacterAppearanceData(a, b, ribbons) =>
|
|
a.app.name mustEqual "Angello"
|
|
a.app.faction mustEqual PlanetSideEmpire.VS
|
|
a.app.sex mustEqual CharacterGender.Male
|
|
a.app.head mustEqual 10
|
|
a.app.voice mustEqual CharacterVoice.Voice2
|
|
a.data.bops mustEqual false
|
|
a.data.v1 mustEqual false
|
|
a.data.v2.isEmpty mustEqual true
|
|
a.data.jammered mustEqual false
|
|
a.data.v4.isEmpty mustEqual true
|
|
a.data.v5.isEmpty mustEqual true
|
|
a.exosuit mustEqual ExoSuitType.MAX
|
|
a.unk5 mustEqual 1
|
|
a.char_id mustEqual 0L
|
|
a.unk7 mustEqual 0
|
|
a.unk8 mustEqual 0
|
|
a.unk9 mustEqual 0
|
|
a.unkA mustEqual 0
|
|
|
|
b.outfit_name mustEqual "Original District"
|
|
b.outfit_logo mustEqual 23
|
|
b.backpack mustEqual true
|
|
b.facingPitch mustEqual -8.4375f
|
|
b.facingYawUpper mustEqual 0
|
|
b.lfs mustEqual false
|
|
b.grenade_state mustEqual GrenadeState.None
|
|
b.is_cloaking mustEqual false
|
|
b.charging_pose mustEqual false
|
|
b.on_zipline.isEmpty mustEqual true
|
|
b.unk0 mustEqual 529687L
|
|
b.unk1 mustEqual false
|
|
b.unk2 mustEqual false
|
|
b.unk3 mustEqual false
|
|
b.unk4 mustEqual false
|
|
b.unk5 mustEqual false
|
|
b.unk6 mustEqual false
|
|
b.unk7 mustEqual false
|
|
|
|
ribbons.upper mustEqual MeritCommendation.Jacking2
|
|
ribbons.middle mustEqual MeritCommendation.ScavengerVS1
|
|
ribbons.lower mustEqual MeritCommendation.AMSSupport4
|
|
ribbons.tos mustEqual MeritCommendation.SixYearVS
|
|
//etc..
|
|
case _ =>
|
|
ko
|
|
}
|
|
|
|
char.health mustEqual 0
|
|
char.armor mustEqual 0
|
|
char.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade
|
|
char.command_rank mustEqual 2
|
|
char.implant_effects.isEmpty mustEqual true
|
|
char.cosmetics match {
|
|
case Some(c: Cosmetics) =>
|
|
c.Styles mustEqual Set(
|
|
PersonalStyle.NoHelmet,
|
|
PersonalStyle.Beret,
|
|
PersonalStyle.Sunglasses,
|
|
PersonalStyle.Earpiece
|
|
)
|
|
case None =>
|
|
ko
|
|
}
|
|
char.unk mustEqual 1
|
|
|
|
hand mustEqual DrawnSlot.Pistol1
|
|
case _ =>
|
|
ko
|
|
}
|
|
case _ =>
|
|
ko
|
|
}
|
|
}
|
|
|
|
"encode" 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 a: Int => CharacterAppearanceA = CharacterAppearanceA(
|
|
BasicCharacterData(
|
|
"ScrawnyRonnie",
|
|
PlanetSideEmpire.TR,
|
|
CharacterGender.Male,
|
|
5,
|
|
CharacterVoice.Voice5
|
|
),
|
|
CommonFieldData(
|
|
PlanetSideEmpire.TR,
|
|
false,
|
|
false,
|
|
false,
|
|
None,
|
|
false,
|
|
None,
|
|
None,
|
|
PlanetSideGUID(0)
|
|
),
|
|
ExoSuitType.Reinforced,
|
|
0,
|
|
30777081L,
|
|
1,
|
|
4,
|
|
0,
|
|
0
|
|
)
|
|
val b: (Boolean, Int) => CharacterAppearanceB = CharacterAppearanceB(
|
|
316554L,
|
|
"Black Beret Armoured Corps",
|
|
23,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
-39.375f,
|
|
0f,
|
|
false,
|
|
GrenadeState.None,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
None
|
|
)
|
|
|
|
val app: Int => CharacterAppearanceData = CharacterAppearanceData(
|
|
a,
|
|
b,
|
|
RibbonBars(
|
|
MeritCommendation.MarkovVeteran,
|
|
MeritCommendation.HeavyInfantry4,
|
|
MeritCommendation.TankBuster7,
|
|
MeritCommendation.SixYearTR
|
|
)
|
|
)
|
|
val char: (Boolean, Boolean) => CharacterData = CharacterData(
|
|
255,
|
|
253,
|
|
UniformStyle.ThirdUpgrade,
|
|
7,
|
|
5,
|
|
List(ImplantEffects.NoEffects),
|
|
Some(Cosmetics(true, true, true, true, false))
|
|
)
|
|
val inv = InventoryData(
|
|
InventoryItemData(
|
|
ObjectClass.plasma_grenade,
|
|
PlanetSideGUID(3662),
|
|
0,
|
|
WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, CommonFieldData()(false))
|
|
) ::
|
|
InventoryItemData(
|
|
ObjectClass.bank,
|
|
PlanetSideGUID(3908),
|
|
1,
|
|
WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, CommonFieldData()(false))
|
|
) ::
|
|
InventoryItemData(
|
|
ObjectClass.mini_chaingun,
|
|
PlanetSideGUID(4164),
|
|
2,
|
|
WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, CommonFieldData()(false))
|
|
) ::
|
|
InventoryItemData(
|
|
ObjectClass.phoenix,
|
|
PlanetSideGUID(3603),
|
|
3,
|
|
WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, CommonFieldData()(false))
|
|
) ::
|
|
InventoryItemData(
|
|
ObjectClass.chainblade,
|
|
PlanetSideGUID(4088),
|
|
4,
|
|
WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, CommonFieldData()(false))
|
|
) ::
|
|
Nil
|
|
)
|
|
val obj = PlayerData(pos, app, char, inv, DrawnSlot.Rifle1)
|
|
|
|
val msg = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(3902), obj)
|
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
|
pkt mustEqual string
|
|
}
|
|
|
|
"encode (seated)" in {
|
|
val a: Int => CharacterAppearanceA = CharacterAppearanceA(
|
|
BasicCharacterData(
|
|
"ScrawnyRonnie",
|
|
PlanetSideEmpire.TR,
|
|
CharacterGender.Male,
|
|
5,
|
|
CharacterVoice.Voice5
|
|
),
|
|
CommonFieldData(
|
|
PlanetSideEmpire.TR,
|
|
false,
|
|
false,
|
|
false,
|
|
None,
|
|
false,
|
|
None,
|
|
None,
|
|
PlanetSideGUID(0)
|
|
),
|
|
ExoSuitType.Reinforced,
|
|
0,
|
|
192L,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
)
|
|
val b: (Boolean, Int) => CharacterAppearanceB = CharacterAppearanceB(
|
|
26L,
|
|
"Black Beret Armoured Corps",
|
|
23,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
-39.375f,
|
|
0f,
|
|
false,
|
|
GrenadeState.None,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
None
|
|
)
|
|
|
|
val app: Int => CharacterAppearanceData = CharacterAppearanceData(
|
|
a,
|
|
b,
|
|
RibbonBars(
|
|
MeritCommendation.MarkovVeteran,
|
|
MeritCommendation.HeavyInfantry4,
|
|
MeritCommendation.TankBuster7,
|
|
MeritCommendation.SixYearTR
|
|
)
|
|
)
|
|
val char: (Boolean, Boolean) => CharacterData = CharacterData(
|
|
255,
|
|
253,
|
|
UniformStyle.ThirdUpgrade,
|
|
5,
|
|
List(ImplantEffects.NoEffects),
|
|
Some(Cosmetics(true, true, true, true, false))
|
|
)
|
|
val inv = InventoryData(
|
|
InventoryItemData(
|
|
ObjectClass.plasma_grenade,
|
|
PlanetSideGUID(3662),
|
|
0,
|
|
WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, CommonFieldData()(false))
|
|
) ::
|
|
InventoryItemData(
|
|
ObjectClass.bank,
|
|
PlanetSideGUID(3908),
|
|
1,
|
|
WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, CommonFieldData()(false))
|
|
) ::
|
|
InventoryItemData(
|
|
ObjectClass.mini_chaingun,
|
|
PlanetSideGUID(4164),
|
|
2,
|
|
WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, CommonFieldData()(false))
|
|
) ::
|
|
InventoryItemData(
|
|
ObjectClass.phoenix,
|
|
PlanetSideGUID(3603),
|
|
3,
|
|
WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, CommonFieldData()(false))
|
|
) ::
|
|
InventoryItemData(
|
|
ObjectClass.chainblade,
|
|
PlanetSideGUID(4088),
|
|
4,
|
|
WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, CommonFieldData()(false))
|
|
) ::
|
|
Nil
|
|
)
|
|
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
|
|
pkt mustEqual string_seated
|
|
}
|
|
|
|
"encode (backpack)" in {
|
|
val pos = PlacementData(
|
|
Vector3(4629.8906f, 6316.4453f, 54.734375f),
|
|
Vector3(0, 0, 126.5625f)
|
|
)
|
|
val a: Int => CharacterAppearanceA = CharacterAppearanceA(
|
|
BasicCharacterData(
|
|
"Angello",
|
|
PlanetSideEmpire.VS,
|
|
CharacterGender.Male,
|
|
10,
|
|
CharacterVoice.Voice2
|
|
),
|
|
CommonFieldData(
|
|
PlanetSideEmpire.VS,
|
|
false,
|
|
true,
|
|
false,
|
|
None,
|
|
false,
|
|
None,
|
|
None,
|
|
PlanetSideGUID(0)
|
|
),
|
|
ExoSuitType.MAX,
|
|
1,
|
|
0L,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
)
|
|
val b: (Boolean, Int) => CharacterAppearanceB = CharacterAppearanceB(
|
|
529687L,
|
|
"Original District",
|
|
23,
|
|
false, //unk1
|
|
true, //backpack
|
|
false, //unk2
|
|
false, //unk3
|
|
false, //unk4
|
|
351.5625f,
|
|
0f, //also: -8.4375f, 0f
|
|
false, //lfs
|
|
GrenadeState.None,
|
|
false, //is_cloaking
|
|
false, //unk5
|
|
false, //unk6
|
|
false, //charging_pose
|
|
false, //unk7
|
|
None
|
|
)
|
|
|
|
val app: Int => CharacterAppearanceData = CharacterAppearanceData(
|
|
a,
|
|
b,
|
|
RibbonBars(
|
|
MeritCommendation.Jacking2,
|
|
MeritCommendation.ScavengerVS1,
|
|
MeritCommendation.AMSSupport4,
|
|
MeritCommendation.SixYearVS
|
|
)
|
|
)
|
|
val char: (Boolean, Boolean) => CharacterData = CharacterData(
|
|
0,
|
|
0,
|
|
UniformStyle.ThirdUpgrade,
|
|
1,
|
|
List(),
|
|
Some(Cosmetics(true, true, true, true, false))
|
|
)
|
|
val obj = PlayerData(pos, app, char, DrawnSlot.Pistol1)
|
|
|
|
val msg = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(3380), obj)
|
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
|
//granular test
|
|
val pkt_bitv = pkt.toBitVector
|
|
val ori_bitv = string_backpack.toBitVector
|
|
pkt_bitv.take(916) mustEqual pkt_bitv.take(916) //skip 4
|
|
pkt_bitv.drop(920) mustEqual pkt_bitv.drop(920)
|
|
//TODO work on CharacterData to make this pass as a single stream
|
|
}
|
|
}
|
|
}
|