added and expanded tests in hopes of increasing code coverage score

added tests for AvatarService and PacketCodingActor; especially PCA tests
This commit is contained in:
FateJH 2017-12-05 00:37:24 -05:00
parent 0e5afe6cfd
commit 3aee0ab4e8
69 changed files with 4534 additions and 3037 deletions

View file

@ -1,2 +1,45 @@
# Too spammy for us # Too spammy for us
comment: off comment: off
ignore:
- "common/src/main/scala/net/psforever/objects/equipment/Ammo.scala"
- "common/src/main/scala/net/psforever/objects/equipment/CItem.scala"
- "common/src/main/scala/net/psforever/objects/equipment/EquipmentSize.scala"
- "common/src/main/scala/net/psforever/objects/equipment/Kits.scala"
- "common/src/main/scala/net/psforever/objects/equipment/SItem.scala"
- "common/src/main/scala/net/psforever/objects/guid/AvailabilityPolicy.scala"
- "common/src/main/scala/net/psforever/objects/vehicles/AccessPermissionGroup.scala"
- "common/src/main/scala/net/psforever/objects/vehicles/SeatArmoRestriction.scala"
- "common/src/main/scala/net/psforever/objects/vehicles/VehicleLockState.scala"
- "common/src/main/scala/net/psforever/objects/Avatars.scala"
- "common/src/main/scala/net/psforever/packet/crypto"
- "common/src/main/scala/net/psforever/packet/game/objectcreate/DrawnSlot.scala"
- "common/src/main/scala/net/psforever/packet/game/objectcreate/DriveState.scala"
- "common/src/main/scala/net/psforever/packet/game/objectcreate/MountItem.scala"
- "common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala"
- "common/src/main/scala/net/psforever/packet/game/objectcreate/Prefab.scala"
- "common/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala"
- "common/src/main/scala/net/psforever/packet/CryptoPacketOpcode.scala"
- "common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala"
- "common/src/main/scala/net/psforever/objects/ObjectType.scala"
- "common/src/main/scala/net/psforever/types/Angular.scala"
- "common/src/main/scala/net/psforever/types/CertificationType.scala"
- "common/src/main/scala/net/psforever/types/ChatMessageType.scala"
- "common/src/main/scala/net/psforever/types/EmoteType.scala"
- "common/src/main/scala/net/psforever/types/ExoSuitType.scala"
- "common/src/main/scala/net/psforever/types/GrenadeState.scala"
- "common/src/main/scala/net/psforever/types/ImplantType.scala"
- "common/src/main/scala/net/psforever/types/MeritCommendation.scala"
- "common/src/main/scala/net/psforever/types/PlanetSideEmpire.scala"
- "common/src/main/scala/net/psforever/types/TransactionType.scala"
- "pslogin/src/main/scala/services/avatar/AvatarAction.scala"
- "pslogin/src/main/scala/services/avatar/AvatarResponse.scala"
- "pslogin/src/main/scala/services/local/LocalAction.scala"
- "pslogin/src/main/scala/services/local/LocalResponse.scala"
- "pslogin/src/main/scala/services/vehicle/VehicleAction.scala"
- "pslogin/src/main/scala/services/vehicle/VehicleResponse.scala"
- "pslogin/src/main/scala/CryptoSessionActor.scala"
- "pslogin/src/main/scala/DatabaseConnector.scala"
- "pslogin/src/main/scala/LoginConfig.scala"
- "pslogin/src/main/scala/MDCContextAware.scala"
- "pslogin/src/main/scala/MDCPropagatingExecutionContext.scala"

View file

@ -778,6 +778,14 @@ object GlobalDefinitions {
* Initialize `AmmoBoxDefinition` globals. * Initialize `AmmoBoxDefinition` globals.
*/ */
private def init_ammo() : Unit = { private def init_ammo() : Unit = {
melee_ammo.Size = EquipmentSize.Blocked
frag_grenade_ammo.Size = EquipmentSize.Blocked
jammer_grenade_ammo.Size = EquipmentSize.Blocked
plasma_grenade_ammo.Size = EquipmentSize.Blocked
bullet_9mm.Capacity = 50 bullet_9mm.Capacity = 50
bullet_9mm.Tile = InventoryTile.Tile33 bullet_9mm.Tile = InventoryTile.Tile33
@ -802,6 +810,8 @@ object GlobalDefinitions {
maelstrom_ammo.Capacity = 50 maelstrom_ammo.Capacity = 50
maelstrom_ammo.Tile = InventoryTile.Tile33 maelstrom_ammo.Tile = InventoryTile.Tile33
phoenix_missile.Size = EquipmentSize.Blocked
striker_missile_ammo.Capacity = 15 striker_missile_ammo.Capacity = 15
striker_missile_ammo.Tile = InventoryTile.Tile44 striker_missile_ammo.Tile = InventoryTile.Tile44
@ -841,6 +851,8 @@ object GlobalDefinitions {
upgrade_canister.Capacity = 100 upgrade_canister.Capacity = 100
upgrade_canister.Tile = InventoryTile.Tile33 upgrade_canister.Tile = InventoryTile.Tile33
trek_ammo.Size = EquipmentSize.Blocked
bullet_35mm.Capacity = 100 bullet_35mm.Capacity = 100
bullet_35mm.Tile = InventoryTile.Tile44 bullet_35mm.Tile = InventoryTile.Tile44

View file

@ -25,7 +25,7 @@ class Player(private val name : String,
private var maxStamina : Int = 100 //does anything affect this? private var maxStamina : Int = 100 //does anything affect this?
private var exosuit : ExoSuitType.Value = ExoSuitType.Standard private var exosuit : ExoSuitType.Value = ExoSuitType.Standard
private val freeHand : EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Any) private val freeHand : EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Inventory)
private val holsters : Array[EquipmentSlot] = Array.fill[EquipmentSlot](5)(new EquipmentSlot) private val holsters : Array[EquipmentSlot] = Array.fill[EquipmentSlot](5)(new EquipmentSlot)
private val fifthSlot : EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Inventory) private val fifthSlot : EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Inventory)
private val inventory : GridInventory = GridInventory() private val inventory : GridInventory = GridInventory()
@ -59,7 +59,6 @@ class Player(private val name : String,
private var cloaked : Boolean = false private var cloaked : Boolean = false
private var backpackAccess : Option[PlanetSideGUID] = None private var backpackAccess : Option[PlanetSideGUID] = None
private var sessionId : Long = 0
private var admin : Boolean = false private var admin : Boolean = false
private var spectator : Boolean = false private var spectator : Boolean = false
@ -498,20 +497,13 @@ class Player(private val name : String,
isBackpack && (backpackAccess.isEmpty || backpackAccess.contains(player.GUID)) isBackpack && (backpackAccess.isEmpty || backpackAccess.contains(player.GUID))
} }
def SessionId : Long = sessionId
def Admin : Boolean = admin def Admin : Boolean = admin
def Spectator : Boolean = spectator def Spectator : Boolean = spectator
def Continent : String = continent
def VehicleSeated : Option[PlanetSideGUID] = vehicleSeated def VehicleSeated : Option[PlanetSideGUID] = vehicleSeated
def VehicleSeated_=(vehicle : Vehicle) : Option[PlanetSideGUID] = { def VehicleSeated_=(guid : PlanetSideGUID) : Option[PlanetSideGUID] = VehicleSeated_=(Some(guid))
vehicleSeated = Some(vehicle.GUID)
VehicleSeated
}
def VehicleSeated_=(guid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = { def VehicleSeated_=(guid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = {
vehicleSeated = guid vehicleSeated = guid
@ -520,16 +512,15 @@ class Player(private val name : String,
def VehicleOwned : Option[PlanetSideGUID] = vehicleOwned def VehicleOwned : Option[PlanetSideGUID] = vehicleOwned
def VehicleOwned_=(vehicle : Vehicle) : Option[PlanetSideGUID] = { def VehicleOwned_=(guid : PlanetSideGUID) : Option[PlanetSideGUID] = VehicleOwned_=(Some(guid))
vehicleOwned = Some(vehicle.GUID)
VehicleOwned
}
def VehicleOwned_=(guid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = { def VehicleOwned_=(guid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = {
vehicleOwned = guid vehicleOwned = guid
VehicleOwned VehicleOwned
} }
def Continent : String = continent
def Continent_=(zoneId : String) : String = { def Continent_=(zoneId : String) : String = {
continent = zoneId continent = zoneId
Continent Continent
@ -570,27 +561,16 @@ object Player {
new Player(name, faction, sex, head, voice) new Player(name, faction, sex, head, voice)
} }
def apply(guid : PlanetSideGUID, name : String, faction : PlanetSideEmpire.Value, sex : CharacterGender.Value, head : Int, voice : Int) : Player = { // /**
val obj = new Player(name, faction, sex, voice, head) // * Change the type of `AvatarDefinition` is used to define the player.
obj.GUID = guid // * @param player the player
obj // * @param avatarDef the player's new definition entry
} // * @return the changed player
// */
/** // def apply(player : Player, avatarDef : AvatarDefinition) : Player = {
* Change the type of `AvatarDefinition` is used to define the player. // player.playerDef = avatarDef
* @param player the player // player
* @param avatarDef the player's new definition entry // }
* @return the changed player
*/
def apply(player : Player, avatarDef : AvatarDefinition) : Player = {
player.playerDef = avatarDef
player
}
def apply(player : Player, sessId : Long) : Player = {
player.sessionId = sessId
player
}
def SuitSetup(player : Player, eSuit : ExoSuitType.Value) : Unit = { def SuitSetup(player : Player, eSuit : ExoSuitType.Value) : Unit = {
val esuitDef : ExoSuitDefinition = ExoSuitDefinition.Select(eSuit) val esuitDef : ExoSuitDefinition = ExoSuitDefinition.Select(eSuit)
@ -604,11 +584,6 @@ object Player {
(0 until 5).foreach(index => { player.Slot(index).Size = esuitDef.Holster(index) }) (0 until 5).foreach(index => { player.Slot(index).Size = esuitDef.Holster(index) })
} }
def ChangeSessionId(player : Player, session : Long) : Long = {
player.sessionId = session
player.SessionId
}
def Administrate(player : Player, isAdmin : Boolean) : Player = { def Administrate(player : Player, isAdmin : Boolean) : Player = {
player.admin = isAdmin player.admin = isAdmin
player player

View file

@ -1,45 +0,0 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.entity
import net.psforever.types.Vector3
import scala.collection.mutable
class MobileWorldEntity extends WorldEntity {
private var coords : mutable.Stack[TimeEntry] = mutable.Stack(TimeEntry.invalid) //history of last #n positional updates
private var orient : mutable.Stack[TimeEntry] = mutable.Stack(TimeEntry.invalid) //history of last #n orientation updates
private var vel : Option[Vector3] = None
def Position : Vector3 = coords.head.entry
def Position_=(vec : Vector3) : Vector3 = {
coords = MobileWorldEntity.pushNewStack(coords, vec, SimpleWorldEntity.validatePositionEntry)
Position
}
def AllPositions : scala.collection.immutable.List[TimeEntry] = coords.toList
def Orientation : Vector3 = orient.head.entry
def Orientation_=(vec : Vector3) : Vector3 = {
orient = MobileWorldEntity.pushNewStack(orient, vec, SimpleWorldEntity.validateOrientationEntry)
Orientation
}
def AllOrientations : scala.collection.immutable.List[TimeEntry] = orient.toList
def Velocity : Option[Vector3] = vel
def Velocity_=(vec : Option[Vector3]) : Option[Vector3] = {
vel = vec
vel
}
override def toString : String = WorldEntity.toString(this)
}
object MobileWorldEntity {
def pushNewStack(lst : mutable.Stack[TimeEntry], newEntry : Vector3, validate : (Vector3) => Vector3) : mutable.Stack[TimeEntry] = {
lst.slice(0, 199).push(TimeEntry(validate(newEntry)))
}
}

View file

@ -1,13 +0,0 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.entity
import net.psforever.types.Vector3
case class TimeEntry(entry : net.psforever.types.Vector3)(implicit time : Long = org.joda.time.DateTime.now.getMillis)
object TimeEntry {
val invalid = TimeEntry(Vector3(0f, 0f, 0f))(0L)
def apply(x : Float, y : Float, z : Float) : TimeEntry =
TimeEntry(Vector3(x, y, z))
}

View file

@ -11,8 +11,7 @@ object EquipmentSize extends Enumeration {
VehicleWeapon, //vehicle-mounted weapons VehicleWeapon, //vehicle-mounted weapons
BFRArmWeapon, //duel arm weapons for bfr BFRArmWeapon, //duel arm weapons for bfr
BFRGunnerWeapon, //gunner seat for bfr BFRGunnerWeapon, //gunner seat for bfr
Inventory, //reserved Inventory //reserved
Any
= Value = Value
/** /**
@ -26,13 +25,13 @@ object EquipmentSize extends Enumeration {
* @param type2 the second size * @param type2 the second size
* @return `true`, if they are equal; `false`, otherwise * @return `true`, if they are equal; `false`, otherwise
*/ */
def isEqual(type1 : EquipmentSize.Value, type2 : EquipmentSize.Value) : Boolean = { def isEqual(type1 : EquipmentSize.Value, type2 : EquipmentSize.Value) : Boolean = {
if(type1 >= Inventory || type2 >= Inventory) { if(type1 == Blocked || type2 == Blocked) {
true
}
else if(type1 == Blocked || type2 == Blocked) {
false false
} }
else if(type1 == Inventory || type2 == Inventory) {
true
}
else { else {
type1 == type2 type1 == type2
} }

View file

@ -4,22 +4,15 @@ package net.psforever.objects.equipment
import scala.collection.mutable import scala.collection.mutable
class FireModeDefinition { class FireModeDefinition {
// private var ammoTypes : mutable.ListBuffer[Ammo.Value] = mutable.ListBuffer[Ammo.Value]() //ammo types valid for this fire mode
private val ammoTypeIndices : mutable.ListBuffer[Int] = mutable.ListBuffer[Int]() //indices pointing to all ammo types used private val ammoTypeIndices : mutable.ListBuffer[Int] = mutable.ListBuffer[Int]() //indices pointing to all ammo types used
private var ammoSlotIndex : Int = 0 //ammunition slot number this fire mode utilizes private var ammoSlotIndex : Int = 0 //ammunition slot number this fire mode utilizes
private var chamber : Int = 1 //how many rounds are queued to be fired at once, e.g., 3 for the Jackhammer's triple burst private var chamber : Int = 1 //how many rounds are queued to be fired at once, e.g., 3 for the Jackhammer's triple burst
private var magazine : Int = 1 //how many rounds are queued for each reload cycle private var magazine : Int = 1 //how many rounds are queued for each reload cycle
private var target : Any = _ //target designation (self? other?) // private var target : Any = _ //target designation (self? other?)
private var resetAmmoIndexOnSwap : Boolean = false //when changing fire modes, do not attempt to match previous mode's ammo type private var resetAmmoIndexOnSwap : Boolean = false //when changing fire modes, do not attempt to match previous mode's ammo type
//damage modifiers will follow here ... //damage modifiers will follow here ...
// def AmmoTypes : mutable.ListBuffer[Ammo.Value] = ammoTypes
//
// def AmmoTypes_=(ammo : Ammo.Value) : mutable.ListBuffer[Ammo.Value] = {
// ammoTypes += ammo
// }
def AmmoSlotIndex : Int = ammoSlotIndex def AmmoSlotIndex : Int = ammoSlotIndex
def AmmoSlotIndex_=(index : Int) : Int = { def AmmoSlotIndex_=(index : Int) : Int = {
@ -47,12 +40,12 @@ class FireModeDefinition {
Magazine Magazine
} }
def Target : Any = target // def Target : Any = target
//
def Target_+(setAsTarget : Any) : Any = { // def Target_+(setAsTarget : Any) : Any = {
target = setAsTarget // target = setAsTarget
Target // Target
} // }
def ResetAmmoIndexOnSwap : Boolean = resetAmmoIndexOnSwap def ResetAmmoIndexOnSwap : Boolean = resetAmmoIndexOnSwap

View file

@ -4,48 +4,6 @@ package net.psforever.objects.guid.source
import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.guid.key.{LoanedKey, SecureKey} import net.psforever.objects.guid.key.{LoanedKey, SecureKey}
trait NumberSourceAccessors {
/**
* Produce an un-modifiable wrapper for the `Monitor` for this number.
* @param number the number
* @return the wrapped `Monitor`
*/
def Get(number : Int) : Option[SecureKey]
/**
* Produce a modifiable wrapper for the `Monitor` for this number, only if the number has not been used.
* The `Monitor` should be updated before being wrapped, if necessary.
* @param number the number
* @return the wrapped `Monitor`, or `None`
*/
def Available(number : Int) : Option[LoanedKey]
/**
* Consume a wrapped `Monitor` and release its number from its previous assignment/use.
* @param monitor the `Monitor`
* @return any object previously using this `Monitor`
*/
def Return(monitor : SecureKey) : Option[IdentifiableEntity] = {
Return(monitor.GUID)
}
/**
* Consume a wrapped `Monitor` and release its number from its previous assignment/use.
* @param monitor the `Monitor`
* @return any object previously using this `Monitor`
*/
def Return(monitor : LoanedKey) : Option[IdentifiableEntity] = {
Return(monitor.GUID)
}
/**
* Consume the number of a `Monitor` and release that number from its previous assignment/use.
* @param number the number
* @return any object previously using this number
*/
def Return(number : Int) : Option[IdentifiableEntity]
}
/** /**
* A `NumberSource` is considered a master "pool" of numbers from which all numbers are available to be drawn. * A `NumberSource` is considered a master "pool" of numbers from which all numbers are available to be drawn.
* The numbers are considered to be exclusive.<br> * The numbers are considered to be exclusive.<br>

View file

@ -15,4 +15,4 @@ final case class MultiPacket(packets : Vector[ByteVector])
object MultiPacket extends Marshallable[MultiPacket] { object MultiPacket extends Marshallable[MultiPacket] {
implicit val codec : Codec[MultiPacket] = ("packets" | vector(variableSizeBytes(uint8L, bytes))).as[MultiPacket] implicit val codec : Codec[MultiPacket] = ("packets" | vector(variableSizeBytes(uint8L, bytes))).as[MultiPacket]
} }

View file

@ -68,4 +68,4 @@ object MultiPacketEx extends Marshallable[MultiPacketEx] {
} }
implicit val codec : Codec[MultiPacketEx] = ("packets" | vector(variableSizeBytesLong(sizeCodec, bytes))).as[MultiPacketEx] implicit val codec : Codec[MultiPacketEx] = ("packets" | vector(variableSizeBytesLong(sizeCodec, bytes))).as[MultiPacketEx]
} }

View file

@ -3,14 +3,14 @@ package net.psforever.packet.control
import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket} import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket}
import scodec.Codec import scodec.Codec
import scodec.bits.{BitVector, ByteOrdering, ByteVector} import scodec.bits.BitVector
import scodec.codecs._ import scodec.codecs._
final case class SlottedMetaAck(slot : Int, subslot : Int) final case class SlottedMetaAck(slot : Int, subslot : Int)
extends PlanetSideControlPacket { extends PlanetSideControlPacket {
type Packet = SlottedMetaAck type Packet = SlottedMetaAck
assert(slot >= 0 && slot <= 7, s"Slot number ($slot) is out of range") assert(slot >= 0 && slot <= 7, s"Slot number ($slot) is out of range") //TODO 7 types of SlottedMeta, 4 types of ResultB?
def opcode = { def opcode = {
val base = ControlPacketOpcode.RelatedB0.id val base = ControlPacketOpcode.RelatedB0.id

View file

@ -3,7 +3,7 @@ package net.psforever.packet.control
import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket} import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket}
import scodec.Codec import scodec.Codec
import scodec.bits.{BitVector, ByteOrdering, ByteVector} import scodec.bits.{BitVector, ByteVector}
import scodec.codecs._ import scodec.codecs._
final case class SlottedMetaPacket(slot : Int, subslot : Int, packet : ByteVector) final case class SlottedMetaPacket(slot : Int, subslot : Int, packet : ByteVector)

View file

@ -71,4 +71,4 @@ object LoginMessage extends Marshallable[LoginMessage] {
("revision" | uint32L) ("revision" | uint32L)
) )
).as[LoginMessage] ).as[LoginMessage]
} }

View file

@ -0,0 +1,27 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class ClientStartTest extends Specification {
val string = hex"0001 00000002 00261e27 000001f0"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ClientStart(nonce) =>
nonce mustEqual 656287232
case _ =>
ko
}
}
"encode" in {
val msg = ClientStart(656287232)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,26 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class ConnectionCloseTest extends Specification {
val string = hex"001D"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ConnectionClose() =>
ok
case _ =>
ko
}
}
"encode" in {
val msg = ConnectionClose()
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -40,4 +40,8 @@ class MultiPacketExTest extends Specification {
"test "+i ! { MultiPacketEx.encode(packets{i}).require.toByteVector mustEqual strings{i} } "test "+i ! { MultiPacketEx.encode(packets{i}).require.toByteVector mustEqual strings{i} }
} }
} }
"sizeCodec description" in {
MultiPacketEx.sizeCodec.toString mustEqual "variable-bit unsigned integer"
}
} }

View file

@ -0,0 +1,38 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class MultiPacketTest extends Specification {
val string = hex"00 03 04 00 15 13 23 3A 00 09 03 E3 00 19 16 6D 56 05 68 05 40 A0 EF 45 00 15 0E 44 00 A0 A2 41 00 00 0F 88 00 06 E4 C0 60 00 00 00 15 E4 32 40 74 72 61 69 6E 69 6E 67 5F 77 65 61 70 6F 6E 73 30 31 13 BD 68 05 53 F6 EF 90 D1 6E 03 14 FE 78 8C 20 1C C0 00 00 1F 00 09 03 E4 6D 56 05 68 05 40 A0 EF 45 00 15 0E 44 30 89 A1 41 00 00 0F 8A 01 00 04 18 EF 80"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case MultiPacket(data) =>
data.size mustEqual 4
data(0) mustEqual hex"00151323"
data(1) mustEqual hex"000903e30019166d5605680540a0ef4500150e4400a0a24100000f880006e4c06000000015e43240747261696e696e675f776561706f6e733031"
data(2) mustEqual hex"bd680553f6ef90d16e0314fe788c201cc00000"
data(3) mustEqual hex"000903e46d5605680540a0ef4500150e443089a14100000f8a01000418ef80"
case _ =>
ko
}
}
"encode" in {
val msg = MultiPacket(
Vector(
hex"00151323",
hex"000903e30019166d5605680540a0ef4500150e4400a0a24100000f880006e4c06000000015e43240747261696e696e675f776561706f6e733031",
hex"bd680553f6ef90d16e0314fe788c201cc00000",
hex"000903e46d5605680540a0ef4500150e443089a14100000f8a01000418ef80"
)
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class SlottedMetaAckTest extends Specification {
val string = hex"00150da4"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case SlottedMetaAck(_, _) =>
ko
case RelatedB0(subslot) => //important!
subslot mustEqual 3492
case _ =>
ko
}
}
"encode" in {
val pkt = SlottedMetaAck(0, 3492)
val msg = PacketCoding.EncodePacket(pkt).require.toByteVector
msg mustEqual string
}
}

View file

@ -0,0 +1,122 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class LoginMessageTest extends Specification {
val string_password = hex"0x01030000000f0000008b4465632020322032303039408061816154000000"
val string_token = hex"0x01030000000f0000008b4465632020322032303039a0a0a0a0a121212121a1a1a1a222222222a2a2a2a323232323a3a3a3a424240040806154000000"
"LoginMessage" should {
"decode (username)" in {
PacketCoding.DecodePacket(string_password).require match {
case LoginMessage(majorVersion, minorVersion, buildDate, username, password, token, revision) =>
majorVersion mustEqual 3
minorVersion mustEqual 15
buildDate mustEqual "Dec 2 2009"
username mustEqual "a"
password mustEqual Some("a")
token mustEqual None
revision mustEqual 84
case _ =>
ko
}
}
"decode (token)" in {
PacketCoding.DecodePacket(string_token).require match {
case LoginMessage(majorVersion, minorVersion, buildDate, username, password, token, revision) =>
majorVersion mustEqual 3
minorVersion mustEqual 15
buildDate mustEqual "Dec 2 2009"
username mustEqual "a"
password mustEqual None
token mustEqual Some("AAAABBBBCCCCDDDDEEEEFFFFGGGGHHH")
revision mustEqual 84
case _ =>
ko
}
}
"encode (username)" in {
val msg = LoginMessage(
3,
15,
"Dec 2 2009",
"a",
Some("a"),
None,
84
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_password
}
}
"encode (token)" in {
val msg = LoginMessage(
3,
15,
"Dec 2 2009",
"a",
None,
Some("AAAABBBBCCCCDDDDEEEEFFFFGGGGHHH"),
84
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_token
}
"encode (both?)" in {
LoginMessage(
3,
15,
"Dec 2 2009",
"a",
Some("a"),
Some("AAAABBBBCCCCDDDDEEEEFFFFGGGGHHH"),
84
) must throwA[IllegalArgumentException]
}
"encode (majorVersion == -1)" in {
LoginMessage(
-1,
15,
"Dec 2 2009",
"a",
Some("a"),
None,
84
) must throwA[IllegalArgumentException]
}
"encode (minorVersion == -1)" in {
LoginMessage(
3,
-1,
"Dec 2 2009",
"a",
Some("a"),
None,
84
) must throwA[IllegalArgumentException]
}
"encode (revision == -1)" in {
LoginMessage(
3,
15,
"Dec 2 2009",
"a",
Some("a"),
None,
-1
) must throwA[IllegalArgumentException]
}
}

View file

@ -0,0 +1,63 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateDetailedMessage, _}
import net.psforever.packet.game.objectcreate._
import scodec.bits._
class ObjectCreateBaseTest extends Specification {
val packet217 = hex"17 F8 00 00 00 BC 8C 10 90 3B 45 C6 FA 94 00 9F F0 00 00 40 00 08 C0 44 00 69 00 66 00 66 00 45" //fake data
val packet218 = hex"18 F8 00 00 00 BC 8C 10 90 3B 45 C6 FA 94 00 9F F0 00 00 40 00 08 C0 44 00 69 00 66 00 66 00 45" //fake data
"ObjectCreateDetailedMessage" should {
"fail to decode" in {
//an invalid bit representation will fail to turn into an object
PacketCoding.DecodePacket(packet217).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 248
cls mustEqual ObjectClass.avatar
guid mustEqual PlanetSideGUID(2497)
parent mustEqual None
data.isDefined mustEqual false
case _ =>
ko
}
}
"fail to encode" in {
//the lack of an object will fail to turn into a bad bitstream
val msg = ObjectCreateMessage(0L, ObjectClass.avatar, PlanetSideGUID(2497), None, None)
PacketCoding.EncodePacket(msg).isFailure mustEqual true
}
}
"ObjectCreateDetailedMessage" should {
"fail to decode" in {
//an invalid bit representation will fail to turn into an object
PacketCoding.DecodePacket(packet218).require match {
case ObjectCreateDetailedMessage(len, cls, guid, parent, data) =>
len mustEqual 248
cls mustEqual ObjectClass.avatar
guid mustEqual PlanetSideGUID(2497)
parent mustEqual None
data.isDefined mustEqual false
case _ =>
ko
}
}
"fail to encode" in {
//the lack of an object will fail to turn into a bad bitstream
val msg = ObjectCreateDetailedMessage(0L, ObjectClass.avatar, PlanetSideGUID(2497), None, None)
PacketCoding.EncodePacket(msg).isFailure mustEqual true
}
}
"StreamBitSize" should {
"have zero size by default" in {
new StreamBitSize() {}.bitsize mustEqual 0L
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -1,576 +0,0 @@
// Copyright (c) 2017 PSForever
package game
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateMessage, _}
import net.psforever.packet.game.objectcreate.{DriveState, _}
import net.psforever.types._
import org.specs2.mutable._
import scodec.bits._
class ObjectCreateMessageVehiclesTest extends Specification {
val string_fury = hex"17 50010000 A79 9D01 FBC1C 12A83 2F06 00 00 21 4400003FC00101140C800C0E40000004048F3600301900000"
val string_ant = hex"17 C2000000 9E0 7C01 6C2D7 65535 CA16 00 00 00 4400003FC000000"
val string_lightning = hex"17 8b010000 df1 5a00 6c2d7 65535 ca16 00 00 00 4400003fc00101300ad8040c4000000408190b801018000002617402070000000"
val string_mediumtransport = hex"17 DA010000 8A2 8301 FBC1C 12A83 2F06 00 00 21 2400003FC079020593F80C2E400000040410148030190000017458050D90000001010401F814064000000"
val string_ams = hex"17 B8010000 970 3D10 002D765535CA16000000 402285BB0037E4100749E1D03000000620D83A0A00000195798741C00000332E40D84800000"
val string_ams_destroyed = hex"17 8D000000 978 3D10 002D765535CA16000000 0"
val string_switchblade = hex"17 93010000 A7B A201 FBC1C12A832F06000021 4400003FC00001013AD3180C0E4000000408330DC03019000006620406072000000"
val string_droppod = hex"17 C1000000 8110B0E00FA9000ACFFFF000000 4400007F83C0900"
val string_orbital_shuttle_1 = hex"17 82000000 0901B026904838000001FE0700"
val string_orbital_shuttle_2 = hex"17 C3000000 B02670402F5AA14F88C210000604000007F8FF03C0"
"decode (fury)" in {
PacketCoding.DecodePacket(string_fury).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 336
cls mustEqual ObjectClass.fury
guid mustEqual PlanetSideGUID(413)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val fury = data.get.asInstanceOf[VehicleData]
fury.basic.pos.coord.x mustEqual 6531.961f
fury.basic.pos.coord.y mustEqual 1872.1406f
fury.basic.pos.coord.z mustEqual 24.734375f
fury.basic.pos.orient.x mustEqual 0f
fury.basic.pos.orient.y mustEqual 0f
fury.basic.pos.orient.z mustEqual 357.1875f
fury.basic.pos.vel.isDefined mustEqual false
fury.basic.faction mustEqual PlanetSideEmpire.VS
fury.basic.unk mustEqual 2
fury.basic.player_guid mustEqual PlanetSideGUID(0)
fury.health mustEqual 255
//
fury.inventory.isDefined mustEqual true
fury.inventory.get.contents.size mustEqual 1
val mounting = fury.inventory.get.contents.head
mounting.objectClass mustEqual ObjectClass.fury_weapon_systema
mounting.guid mustEqual PlanetSideGUID(400)
mounting.parentSlot mustEqual 1
mounting.obj.isInstanceOf[WeaponData] mustEqual true
val weapon = mounting.obj.asInstanceOf[WeaponData]
weapon.unk1 mustEqual 0x6
weapon.unk2 mustEqual 0x8
weapon.fire_mode mustEqual 0
weapon.ammo.size mustEqual 1
val ammo = weapon.ammo.head
ammo.objectClass mustEqual ObjectClass.hellfire_ammo
ammo.guid mustEqual PlanetSideGUID(432)
ammo.parentSlot mustEqual 0
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8
case _ =>
ko
}
}
"decode (ant)" in {
PacketCoding.DecodePacket(string_ant).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 194L
cls mustEqual ObjectClass.ant
guid mustEqual PlanetSideGUID(380)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val ant = data.get.asInstanceOf[VehicleData]
ant.basic.pos.coord.x mustEqual 3674.8438f
ant.basic.pos.coord.y mustEqual 2726.789f
ant.basic.pos.coord.z mustEqual 91.15625f
ant.basic.pos.orient.x mustEqual 0f
ant.basic.pos.orient.y mustEqual 0f
ant.basic.pos.orient.z mustEqual 90.0f
ant.basic.faction mustEqual PlanetSideEmpire.VS
ant.basic.unk mustEqual 2
ant.basic.player_guid mustEqual PlanetSideGUID(0)
ant.health mustEqual 255
ant.driveState mustEqual DriveState.Mobile
case _ =>
ko
}
}
"decode (lightning)" in {
PacketCoding.DecodePacket(string_lightning).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 395L
cls mustEqual ObjectClass.lightning
guid mustEqual PlanetSideGUID(90)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val lightning = data.get.asInstanceOf[VehicleData]
lightning.basic.pos.coord.x mustEqual 3674.8438f
lightning.basic.pos.coord.y mustEqual 2726.789f
lightning.basic.pos.coord.z mustEqual 91.15625f
lightning.basic.pos.orient.x mustEqual 0f
lightning.basic.pos.orient.y mustEqual 0f
lightning.basic.pos.orient.z mustEqual 90.0f
lightning.basic.faction mustEqual PlanetSideEmpire.VS
lightning.basic.unk mustEqual 2
lightning.basic.player_guid mustEqual PlanetSideGUID(0)
lightning.health mustEqual 255
lightning.inventory.isDefined mustEqual true
lightning.inventory.get.contents.size mustEqual 1
val mounting = lightning.inventory.get.contents.head
mounting.objectClass mustEqual ObjectClass.lightning_weapon_system
mounting.guid mustEqual PlanetSideGUID(91)
mounting.parentSlot mustEqual 1
mounting.obj.isInstanceOf[WeaponData] mustEqual true
val weapon = mounting.obj.asInstanceOf[WeaponData]
weapon.unk1 mustEqual 0x4
weapon.unk2 mustEqual 0x8
weapon.fire_mode mustEqual 0
weapon.ammo.size mustEqual 2
//0
var ammo = weapon.ammo.head
ammo.objectClass mustEqual ObjectClass.bullet_75mm
ammo.guid mustEqual PlanetSideGUID(92)
ammo.parentSlot mustEqual 0
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x0
//1
ammo = weapon.ammo(1)
ammo.objectClass mustEqual ObjectClass.bullet_25mm
ammo.guid mustEqual PlanetSideGUID(93)
ammo.parentSlot mustEqual 1
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x0
case _ =>
ko
}
}
"decode (medium transport)" in {
PacketCoding.DecodePacket(string_mediumtransport).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 474L
cls mustEqual ObjectClass.mediumtransport
guid mustEqual PlanetSideGUID(387)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val deliverer = data.get.asInstanceOf[VehicleData]
deliverer.basic.pos.coord.x mustEqual 6531.961f
deliverer.basic.pos.coord.y mustEqual 1872.1406f
deliverer.basic.pos.coord.z mustEqual 24.734375f
deliverer.basic.pos.orient.x mustEqual 0f
deliverer.basic.pos.orient.y mustEqual 0f
deliverer.basic.pos.orient.z mustEqual 357.1875f
deliverer.basic.faction mustEqual PlanetSideEmpire.NC
deliverer.basic.unk mustEqual 2
deliverer.basic.player_guid mustEqual PlanetSideGUID(0)
deliverer.unk1 mustEqual 0
deliverer.health mustEqual 255
deliverer.unk2 mustEqual false
deliverer.driveState mustEqual DriveState.State7
deliverer.unk3 mustEqual true
deliverer.unk4 mustEqual None
deliverer.unk5 mustEqual false
deliverer.inventory.isDefined mustEqual true
deliverer.inventory.get.contents.size mustEqual 2
//0
var mounting = deliverer.inventory.get.contents.head
mounting.objectClass mustEqual ObjectClass.mediumtransport_weapon_systemA
mounting.guid mustEqual PlanetSideGUID(383)
mounting.parentSlot mustEqual 5
mounting.obj.isInstanceOf[WeaponData] mustEqual true
var weapon = mounting.obj.asInstanceOf[WeaponData]
weapon.unk1 mustEqual 0x6
weapon.unk2 mustEqual 0x8
weapon.fire_mode mustEqual 0
weapon.ammo.size mustEqual 1
var ammo = weapon.ammo.head
ammo.objectClass mustEqual ObjectClass.bullet_20mm
ammo.guid mustEqual PlanetSideGUID(420)
ammo.parentSlot mustEqual 0
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8
//1
mounting = deliverer.inventory.get.contents(1)
mounting.objectClass mustEqual ObjectClass.mediumtransport_weapon_systemB
mounting.guid mustEqual PlanetSideGUID(556)
mounting.parentSlot mustEqual 6
mounting.obj.isInstanceOf[WeaponData] mustEqual true
weapon = mounting.obj.asInstanceOf[WeaponData]
weapon.unk1 mustEqual 0x6
weapon.unk2 mustEqual 0x8
weapon.fire_mode mustEqual 0
weapon.ammo.size mustEqual 1
ammo = weapon.ammo.head
ammo.objectClass mustEqual ObjectClass.bullet_20mm
ammo.guid mustEqual PlanetSideGUID(575)
ammo.parentSlot mustEqual 0
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8
case _ =>
ko
}
}
"decode (ams)" in {
PacketCoding.DecodePacket(string_ams).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 440L
cls mustEqual ObjectClass.ams
guid mustEqual PlanetSideGUID(4157)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val ams = data.get.asInstanceOf[VehicleData]
ams.basic.pos.coord.x mustEqual 3674.0f
ams.basic.pos.coord.y mustEqual 2726.789f
ams.basic.pos.coord.z mustEqual 91.15625f
ams.basic.pos.orient.x mustEqual 0f
ams.basic.pos.orient.y mustEqual 0f
ams.basic.pos.orient.z mustEqual 90.0f
ams.basic.faction mustEqual PlanetSideEmpire.VS
ams.basic.unk mustEqual 0
ams.basic.player_guid mustEqual PlanetSideGUID(34082)
ams.unk1 mustEqual 2
ams.health mustEqual 236
ams.unk2 mustEqual false
ams.driveState mustEqual DriveState.Deployed
ams.inventory.isDefined mustEqual true
val inv = ams.inventory.get.contents
inv.head.objectClass mustEqual ObjectClass.matrix_terminalc
inv.head.guid mustEqual PlanetSideGUID(3663)
inv.head.parentSlot mustEqual 1
inv.head.obj.isInstanceOf[CommonTerminalData] mustEqual true
inv(1).objectClass mustEqual ObjectClass.ams_respawn_tube
inv(1).guid mustEqual PlanetSideGUID(3638)
inv(1).parentSlot mustEqual 2
inv(1).obj.isInstanceOf[CommonTerminalData] mustEqual true
inv(2).objectClass mustEqual ObjectClass.order_terminala
inv(2).guid mustEqual PlanetSideGUID(3827)
inv(2).parentSlot mustEqual 3
inv(2).obj.isInstanceOf[CommonTerminalData] mustEqual true
inv(3).objectClass mustEqual ObjectClass.order_terminalb
inv(3).guid mustEqual PlanetSideGUID(3556)
inv(3).parentSlot mustEqual 4
inv(3).obj.isInstanceOf[CommonTerminalData] mustEqual true
case _ =>
ko
}
}
"decode (ams, destroyed)" in {
PacketCoding.DecodePacket(string_ams_destroyed).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 141L
cls mustEqual ObjectClass.ams_destroyed
guid mustEqual PlanetSideGUID(4157)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DestroyedVehicleData] mustEqual true
val dams = data.get.asInstanceOf[DestroyedVehicleData]
dams.pos.coord.x mustEqual 3674.0f
dams.pos.coord.y mustEqual 2726.789f
dams.pos.coord.z mustEqual 91.15625f
dams.pos.orient.x mustEqual 0f
dams.pos.orient.y mustEqual 0f
dams.pos.orient.z mustEqual 90.0f
case _ =>
ko
}
}
"decode (switchblade)" in {
PacketCoding.DecodePacket(string_switchblade).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 403L
cls mustEqual ObjectClass.switchblade
guid mustEqual PlanetSideGUID(418)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val switchblade = data.get.asInstanceOf[VehicleData]
switchblade.basic.pos.coord.x mustEqual 6531.961f
switchblade.basic.pos.coord.y mustEqual 1872.1406f
switchblade.basic.pos.coord.z mustEqual 24.734375f
switchblade.basic.pos.orient.x mustEqual 0f
switchblade.basic.pos.orient.y mustEqual 0f
switchblade.basic.pos.orient.z mustEqual 357.1875f
switchblade.basic.faction mustEqual PlanetSideEmpire.VS
switchblade.basic.unk mustEqual 2
switchblade.health mustEqual 255
switchblade.driveState mustEqual DriveState.Mobile
switchblade.inventory.isDefined mustEqual true
switchblade.inventory.get.contents.size mustEqual 1
//0
val weapon = switchblade.inventory.get.contents.head
weapon.objectClass mustEqual ObjectClass.scythe
weapon.guid mustEqual PlanetSideGUID(355)
weapon.parentSlot mustEqual 1
weapon.obj.asInstanceOf[WeaponData].unk1 mustEqual 0x6
weapon.obj.asInstanceOf[WeaponData].unk2 mustEqual 0x8
weapon.obj.asInstanceOf[WeaponData].ammo.size mustEqual 2
//ammo-0
var ammo = weapon.obj.asInstanceOf[WeaponData].ammo.head
ammo.objectClass mustEqual ObjectClass.ancient_ammo_vehicle
ammo.guid mustEqual PlanetSideGUID(366)
ammo.parentSlot mustEqual 0
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8
//ammo-1
ammo = weapon.obj.asInstanceOf[WeaponData].ammo(1)
ammo.objectClass mustEqual ObjectClass.ancient_ammo_vehicle
ammo.guid mustEqual PlanetSideGUID(385)
ammo.parentSlot mustEqual 1
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8
case _ =>
ko
}
}
"decode (droppod)" in {
PacketCoding.DecodePacket(string_droppod).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 193L
cls mustEqual ObjectClass.droppod
guid mustEqual PlanetSideGUID(3595)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DroppodData] mustEqual true
val droppod = data.get.asInstanceOf[DroppodData]
droppod.basic.pos.coord.x mustEqual 5108.0f
droppod.basic.pos.coord.y mustEqual 6164.0f
droppod.basic.pos.coord.z mustEqual 1023.9844f
droppod.basic.pos.orient.x mustEqual 0f
droppod.basic.pos.orient.y mustEqual 0f
droppod.basic.pos.orient.z mustEqual 90.0f
droppod.basic.unk mustEqual 2
droppod.basic.player_guid mustEqual PlanetSideGUID(0)
droppod.burn mustEqual false
droppod.health mustEqual 255
case _ =>
ko
}
}
"decode (shuttle 1)" in {
PacketCoding.DecodePacket(string_orbital_shuttle_1).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 130
cls mustEqual ObjectClass.orbital_shuttle
guid mustEqual PlanetSideGUID(1129)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(786)
parent.get.slot mustEqual 3
data.isDefined mustEqual true
data.get.isInstanceOf[OrbitalShuttleData] mustEqual true
data.get.asInstanceOf[OrbitalShuttleData].faction mustEqual PlanetSideEmpire.VS
data.get.asInstanceOf[OrbitalShuttleData].pos.isDefined mustEqual false
case _ =>
ko
}
}
"decode (shuttle 2)" in {
PacketCoding.DecodePacket(string_orbital_shuttle_2).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 195
cls mustEqual ObjectClass.orbital_shuttle
guid mustEqual PlanetSideGUID(1127)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[OrbitalShuttleData] mustEqual true
val shuttle = data.get.asInstanceOf[OrbitalShuttleData]
shuttle.faction mustEqual PlanetSideEmpire.VS
shuttle.pos.isDefined mustEqual true
shuttle.pos.get.coord.x mustEqual 5610.0156f
shuttle.pos.get.coord.y mustEqual 4255.258f
shuttle.pos.get.coord.z mustEqual 134.1875f
shuttle.pos.get.orient.x mustEqual 0f
shuttle.pos.get.orient.y mustEqual 0f
shuttle.pos.get.orient.z mustEqual 180.0f
case _ =>
ko
}
}
"encode (fury)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
PlanetSideEmpire.VS, 2
),
0,
255,
false, false,
DriveState.Mobile,
false, false, false,
None,
Some(InventoryData(
InventoryItemData(ObjectClass.fury_weapon_systema, PlanetSideGUID(400), 1,
WeaponData(0x6, 0x8, 0, ObjectClass.hellfire_ammo, PlanetSideGUID(432), 0, AmmoBoxData(0x8))
) :: Nil
))
)(VehicleFormat.Normal)
val msg = ObjectCreateMessage(ObjectClass.fury, PlanetSideGUID(413), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_fury
}
"encode (ant)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 2
),
0,
255,
false, false,
DriveState.Mobile,
false, false, false,
Some(UtilityVehicleData(0)),
None
)(VehicleFormat.Utility)
val msg = ObjectCreateMessage(ObjectClass.ant, PlanetSideGUID(380), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ant
}
"encode (lightning)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 2
),
0,
255,
false, false,
DriveState.Mobile,
false, false, false,
None,
Some(InventoryData(
InventoryItemData(ObjectClass.lightning_weapon_system, PlanetSideGUID(91), 1,
WeaponData(4, 8, 0, ObjectClass.bullet_75mm, PlanetSideGUID(92), 0, AmmoBoxData(), ObjectClass.bullet_25mm, PlanetSideGUID(93), 1, AmmoBoxData())
) :: Nil
))
)(VehicleFormat.Normal)
val msg = ObjectCreateMessage(ObjectClass.lightning, PlanetSideGUID(90), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_lightning
}
"encode (medium transport)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
PlanetSideEmpire.NC, 2
),
0,
255,
false, false,
DriveState.State7,
true, false, false,
None,
Some(InventoryData(
InventoryItemData(ObjectClass.mediumtransport_weapon_systemA, PlanetSideGUID(383), 5,
WeaponData(6, 8, ObjectClass.bullet_20mm, PlanetSideGUID(420), 0, AmmoBoxData(8))
) ::
InventoryItemData(ObjectClass.mediumtransport_weapon_systemB, PlanetSideGUID(556), 6,
WeaponData(6, 8, ObjectClass.bullet_20mm, PlanetSideGUID(575), 0, AmmoBoxData(8))
) :: Nil
))
)(VehicleFormat.Normal)
val msg = ObjectCreateMessage(ObjectClass.mediumtransport, PlanetSideGUID(387), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_mediumtransport
}
"encode (ams)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(3674.0f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 0,
PlanetSideGUID(34082)
),
2,
236,
false, false,
DriveState.Deployed,
false, true, true,
Some(UtilityVehicleData(60)), //what does this mean?
Some(InventoryData(List(
InternalSlot(ObjectClass.matrix_terminalc, PlanetSideGUID(3663), 1, CommonTerminalData(PlanetSideEmpire.VS)),
InternalSlot(ObjectClass.ams_respawn_tube, PlanetSideGUID(3638), 2, CommonTerminalData(PlanetSideEmpire.VS)),
InternalSlot(ObjectClass.order_terminala, PlanetSideGUID(3827), 3, CommonTerminalData(PlanetSideEmpire.VS)),
InternalSlot(ObjectClass.order_terminalb, PlanetSideGUID(3556), 4, CommonTerminalData(PlanetSideEmpire.VS))
)))
)(VehicleFormat.Utility)
val msg = ObjectCreateMessage(ObjectClass.ams, PlanetSideGUID(4157), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ams
}
"encode (ams, destroyed)" in {
val obj = DestroyedVehicleData(PlacementData(3674.0f, 2726.789f, 91.15625f, 0f, 0f, 90.0f))
val msg = ObjectCreateMessage(ObjectClass.ams_destroyed, PlanetSideGUID(4157), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ams_destroyed
}
"encode (switchblade)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
PlanetSideEmpire.VS,
2
),
0,
255,
false, false,
DriveState.Mobile,
false, false, false,
Some(VariantVehicleData(0)),
Some(InventoryData(
InventoryItemData(ObjectClass.scythe, PlanetSideGUID(355), 1,
WeaponData(0x6, 0x8, 0, ObjectClass.ancient_ammo_vehicle, PlanetSideGUID(366), 0, AmmoBoxData(0x8), ObjectClass.ancient_ammo_vehicle, PlanetSideGUID(385), 1, AmmoBoxData(0x8))
) :: Nil
))
)(VehicleFormat.Variant)
val msg = ObjectCreateMessage(ObjectClass.switchblade, PlanetSideGUID(418), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_switchblade
}
"encode (droppod)" in {
val obj = DroppodData(
CommonFieldData(
PlacementData(5108.0f, 6164.0f, 1023.9844f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS,
2
)
)
val msg = ObjectCreateMessage(ObjectClass.droppod, PlanetSideGUID(3595), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_droppod
}
"encode (shuttle 1)" in {
val obj = OrbitalShuttleData(PlanetSideEmpire.VS)
val msg = ObjectCreateMessage(ObjectClass.orbital_shuttle, PlanetSideGUID(1129), ObjectCreateMessageParent(PlanetSideGUID(786), 3), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_orbital_shuttle_1
}
"encode (shuttle 2)" in {
val obj = OrbitalShuttleData(PlacementData(5610.0156f, 4255.258f, 134.1875f, 0f, 0f, 180.0f), PlanetSideEmpire.VS)
val msg = ObjectCreateMessage(ObjectClass.orbital_shuttle, PlanetSideGUID(1127), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_orbital_shuttle_2
}
}

View file

@ -0,0 +1,77 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import org.specs2.mutable._
import scodec.bits._
class ACEDataTest extends Specification {
val string_ace_held = hex"17 76000000 0406900650C80480000000"
val string_ace_dropped = hex"17 AF000000 90024113B329C5D5A2D1200005B440000000"
"ACEData" should {
"decode (held)" in {
PacketCoding.DecodePacket(string_ace_held).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 118
cls mustEqual ObjectClass.ace
guid mustEqual PlanetSideGUID(3173)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(3336)
parent.get.slot mustEqual 0
data.isDefined mustEqual true
data.get.isInstanceOf[ACEData] mustEqual true
val ace = data.get.asInstanceOf[ACEData]
ace.unk1 mustEqual 4
ace.unk2 mustEqual 8
ace.unk3 mustEqual 0
case _ =>
ko
}
}
"decode (dropped)" in {
PacketCoding.DecodePacket(string_ace_dropped).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 175
cls mustEqual ObjectClass.ace
guid mustEqual PlanetSideGUID(4388)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DroppedItemData[_]] mustEqual true
val drop = data.get.asInstanceOf[DroppedItemData[_]]
drop.pos.coord.x mustEqual 4708.461f
drop.pos.coord.y mustEqual 5547.539f
drop.pos.coord.z mustEqual 72.703125f
drop.pos.orient.x mustEqual 0f
drop.pos.orient.y mustEqual 0f
drop.pos.orient.z mustEqual 194.0625f
drop.obj.isInstanceOf[ACEData] mustEqual true
val ace = drop.obj.asInstanceOf[ACEData]
ace.unk1 mustEqual 8
ace.unk2 mustEqual 8
case _ =>
ko
}
}
"encode (held)" in {
val obj = ACEData(4, 8)
val msg = ObjectCreateMessage(ObjectClass.ace, PlanetSideGUID(3173), ObjectCreateMessageParent(PlanetSideGUID(3336), 0), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ace_held
}
"encode (dropped)" in {
val obj = DroppedItemData(
PlacementData(4708.461f, 5547.539f, 72.703125f, 0f, 0f, 194.0625f),
ACEData(8, 8)
)
val msg = ObjectCreateMessage(ObjectClass.ace, PlanetSideGUID(4388), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ace_dropped
}
}
}

View file

@ -0,0 +1,53 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
import scodec.bits._
class AegisShieldGeneratorDataTest extends Specification {
val string_aegis = hex"17 10010000 F80FC09 9DF96 0C676 801C 00 00 00 443E09FF0000000000000000000000000"
"AegisShieldGeneratorData" should {
"decode" in {
PacketCoding.DecodePacket(string_aegis).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 272
cls mustEqual ObjectClass.deployable_shield_generator
guid mustEqual PlanetSideGUID(2556)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[AegisShieldGeneratorData] mustEqual true
val aegis = data.get.asInstanceOf[AegisShieldGeneratorData]
aegis.deploy.pos.coord.x mustEqual 3571.2266f
aegis.deploy.pos.coord.y mustEqual 3278.0938f
aegis.deploy.pos.coord.z mustEqual 114.0f
aegis.deploy.pos.orient.x mustEqual 0f
aegis.deploy.pos.orient.y mustEqual 0f
aegis.deploy.pos.orient.z mustEqual 90.0f
aegis.deploy.faction mustEqual PlanetSideEmpire.VS
aegis.deploy.unk mustEqual 2
aegis.health mustEqual 255
aegis.deploy.player_guid mustEqual PlanetSideGUID(2366)
case _ =>
ko
}
}
"encode" in {
val obj = AegisShieldGeneratorData(
CommonFieldData(
PlacementData(3571.2266f, 3278.0938f, 114.0f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 2, PlanetSideGUID(2366)
),
255
)
val msg = ObjectCreateMessage(ObjectClass.deployable_shield_generator, PlanetSideGUID(2556), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_aegis
}
}
}

View file

@ -0,0 +1,48 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import org.specs2.mutable._
import scodec.bits._
class AmmoBoxDataTest extends Specification {
val string_shotgunshell_dropped = hex"17 A5000000 F9A7D0D 5E269 BED5A F114 0000596000000"
"AmmoBoxData" should {
"decode (shotgun shells, dropped)" in {
PacketCoding.DecodePacket(string_shotgunshell_dropped).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 165
cls mustEqual ObjectClass.shotgun_shell
guid mustEqual PlanetSideGUID(3453)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DroppedItemData[_]] mustEqual true
val drop = data.get.asInstanceOf[DroppedItemData[_]]
drop.pos.coord.x mustEqual 4684.7344f
drop.pos.coord.y mustEqual 5547.4844f
drop.pos.coord.z mustEqual 83.765625f
drop.pos.orient.x mustEqual 0f
drop.pos.orient.y mustEqual 0f
drop.pos.orient.z mustEqual 199.6875f
drop.obj.isInstanceOf[AmmoBoxData] mustEqual true
val box = drop.obj.asInstanceOf[AmmoBoxData]
box.unk mustEqual 0
case _ =>
ko
}
}
"encode (shotgun shells, dropped)" in {
val obj = DroppedItemData(
PlacementData(4684.7344f, 5547.4844f, 83.765625f, 0f, 0f, 199.6875f),
AmmoBoxData()
)
val msg = ObjectCreateMessage(ObjectClass.shotgun_shell, PlanetSideGUID(3453), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_shotgunshell_dropped
}
}
}

View file

@ -0,0 +1,38 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import org.specs2.mutable._
import scodec.bits._
class BoomerTriggerDataTest extends Specification {
val string_boomertrigger = hex"17 76000000 58084A8100E80C00000000" //reconstructed from an inventory entry
"BoomerTriggerData" should {
"decode (held)" in {
PacketCoding.DecodePacket(string_boomertrigger).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 118
cls mustEqual ObjectClass.boomer_trigger
guid mustEqual PlanetSideGUID(3600)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(4272)
parent.get.slot mustEqual 0
data.isDefined mustEqual true
data.get.isInstanceOf[BoomerTriggerData] mustEqual true
data.get.asInstanceOf[BoomerTriggerData].unk mustEqual 0
case _ =>
ko
}
}
"encode (held)" in {
val obj = BoomerTriggerData(0)
val msg = ObjectCreateMessage(ObjectClass.boomer_trigger, PlanetSideGUID(3600), ObjectCreateMessageParent(PlanetSideGUID(4272), 0), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_boomertrigger
}
}
}

View file

@ -0,0 +1,48 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
import scodec.bits._
class CaptureFlagDataTest extends Specification {
val string_captureflag = hex"17 E5000000 CE8EA10 04A47 B818A FE0E 00 00 0F 24000015000400160B09000" //LLU for Qumu on Amerish
"CaptureFlagData" in {
"decode" in {
PacketCoding.DecodePacket(string_captureflag).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 229
cls mustEqual ObjectClass.capture_flag
guid mustEqual PlanetSideGUID(4330)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[CaptureFlagData] mustEqual true
val flag = data.get.asInstanceOf[CaptureFlagData]
flag.pos.coord.x mustEqual 3912.0312f
flag.pos.coord.y mustEqual 5169.4375f
flag.pos.coord.z mustEqual 59.96875f
flag.pos.orient.x mustEqual 0f
flag.pos.orient.y mustEqual 0f
flag.pos.orient.z mustEqual 47.8125f
flag.faction mustEqual PlanetSideEmpire.NC
flag.unk1 mustEqual 21
flag.unk2 mustEqual 4
flag.unk3 mustEqual 2838
flag.unk4 mustEqual 9
case _ =>
ko
}
}
"encode" in {
val obj = CaptureFlagData(PlacementData(3912.0312f, 5169.4375f, 59.96875f, 0f, 0f, 47.8125f), PlanetSideEmpire.NC, 21, 4, 2838, 9)
val msg = ObjectCreateMessage(ObjectClass.capture_flag, PlanetSideGUID(4330), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_captureflag
}
}
}

View file

@ -0,0 +1,282 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types._
import org.specs2.mutable._
import scodec.bits._
class CharacterDataTest extends Specification {
val string_character = hex"17 73070000 BC8 3E0F 6C2D7 65535 CA16 00 00 09 9741E4F804000000 234530063007200610077006E00790052006F006E006E0069006500 220B7 E67B540404001000000000022B50100 268042006C00610063006B002000420065007200650074002000410072006D006F007500720065006400200043006F00720070007300 1700E0030050040003BC00000234040001A004000 3FFF67A8F A0A5424E0E800000000080952A9C3A03000001081103E040000000A023782F1080C0000016244108200000000808382403A030000014284C3A0C0000000202512F00B80C00000578F80F840000000280838B3C320300000080"
val string_character_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_character).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.isDefined mustEqual true
data.get.isInstanceOf[CharacterData] mustEqual true
val pc = data.get.asInstanceOf[CharacterData]
pc.appearance.pos.coord.x mustEqual 3674.8438f
pc.appearance.pos.coord.y mustEqual 2726.789f
pc.appearance.pos.coord.z mustEqual 91.15625f
pc.appearance.pos.orient.x mustEqual 0f
pc.appearance.pos.orient.y mustEqual 0f
pc.appearance.pos.orient.z mustEqual 64.6875f
pc.appearance.pos.vel.isDefined mustEqual true
pc.appearance.pos.vel.get.x mustEqual 1.4375f
pc.appearance.pos.vel.get.y mustEqual -0.4375f
pc.appearance.pos.vel.get.z mustEqual 0f
pc.appearance.basic_appearance.name mustEqual "ScrawnyRonnie"
pc.appearance.basic_appearance.faction mustEqual PlanetSideEmpire.TR
pc.appearance.basic_appearance.sex mustEqual CharacterGender.Male
pc.appearance.basic_appearance.head mustEqual 5
pc.appearance.basic_appearance.voice mustEqual 5
pc.appearance.voice2 mustEqual 3
pc.appearance.black_ops mustEqual false
pc.appearance.jammered mustEqual false
pc.appearance.exosuit mustEqual ExoSuitType.Reinforced
pc.appearance.outfit_name mustEqual "Black Beret Armoured Corps"
pc.appearance.outfit_logo mustEqual 23
pc.appearance.facingPitch mustEqual 340.3125f
pc.appearance.facingYawUpper mustEqual 0
pc.appearance.lfs mustEqual false
pc.appearance.grenade_state mustEqual GrenadeState.None
pc.appearance.is_cloaking mustEqual false
pc.appearance.charging_pose mustEqual false
pc.appearance.on_zipline mustEqual false
pc.appearance.ribbons.upper mustEqual MeritCommendation.MarkovVeteran
pc.appearance.ribbons.middle mustEqual MeritCommendation.HeavyInfantry4
pc.appearance.ribbons.lower mustEqual MeritCommendation.TankBuster7
pc.appearance.ribbons.tos mustEqual MeritCommendation.SixYearTR
pc.health mustEqual 255
pc.armor mustEqual 253
pc.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade
pc.command_rank mustEqual 5
pc.implant_effects.isDefined mustEqual true
pc.implant_effects.get mustEqual ImplantEffects.NoEffects
pc.cosmetics.isDefined mustEqual true
pc.cosmetics.get.no_helmet mustEqual true
pc.cosmetics.get.beret mustEqual true
pc.cosmetics.get.sunglasses mustEqual true
pc.cosmetics.get.earpiece mustEqual true
pc.cosmetics.get.brimmed_cap mustEqual false
//short test of inventory items
pc.inventory.isDefined mustEqual true
val contents = pc.inventory.get.contents
contents.size mustEqual 5
//0
contents.head.objectClass mustEqual ObjectClass.plasma_grenade
contents.head.guid mustEqual PlanetSideGUID(3662)
contents.head.parentSlot mustEqual 0
contents.head.obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
contents.head.obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.plasma_grenade_ammo
contents.head.obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3751)
//1
contents(1).objectClass mustEqual ObjectClass.bank
contents(1).guid mustEqual PlanetSideGUID(3908)
contents(1).parentSlot mustEqual 1
contents(1).obj.asInstanceOf[WeaponData].fire_mode mustEqual 1
contents(1).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.armor_canister
contents(1).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(4143)
//2
contents(2).objectClass mustEqual ObjectClass.mini_chaingun
contents(2).guid mustEqual PlanetSideGUID(4164)
contents(2).parentSlot mustEqual 2
contents(2).obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
contents(2).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.bullet_9mm
contents(2).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3728)
//3
contents(3).objectClass mustEqual ObjectClass.phoenix //actually, a decimator
contents(3).guid mustEqual PlanetSideGUID(3603)
contents(3).parentSlot mustEqual 3
contents(3).obj.asInstanceOf[WeaponData].fire_mode mustEqual 0
contents(3).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.phoenix_missile
contents(3).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3056)
//4
contents(4).objectClass mustEqual ObjectClass.chainblade
contents(4).guid mustEqual PlanetSideGUID(4088)
contents(4).parentSlot mustEqual 4
contents(4).obj.asInstanceOf[WeaponData].fire_mode mustEqual 1
contents(4).obj.asInstanceOf[WeaponData].ammo.head.objectClass mustEqual ObjectClass.melee_ammo
contents(4).obj.asInstanceOf[WeaponData].ammo.head.guid mustEqual PlanetSideGUID(3279)
pc.drawn_slot mustEqual DrawnSlot.Rifle1
case _ =>
ko
}
}
"decode (backpack)" in {
PacketCoding.DecodePacket(string_character_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.isDefined mustEqual true
data.get.isInstanceOf[CharacterData] mustEqual true
val pc = data.get.asInstanceOf[CharacterData]
pc.appearance.pos.coord.x mustEqual 4629.8906f
pc.appearance.pos.coord.y mustEqual 6316.4453f
pc.appearance.pos.coord.z mustEqual 54.734375f
pc.appearance.pos.orient.x mustEqual 0f
pc.appearance.pos.orient.y mustEqual 0f
pc.appearance.pos.orient.z mustEqual 126.5625f
pc.appearance.pos.vel.isDefined mustEqual false
pc.appearance.basic_appearance.name mustEqual "Angello"
pc.appearance.basic_appearance.faction mustEqual PlanetSideEmpire.VS
pc.appearance.basic_appearance.sex mustEqual CharacterGender.Male
pc.appearance.basic_appearance.head mustEqual 10
pc.appearance.basic_appearance.voice mustEqual 2
pc.appearance.voice2 mustEqual 0
pc.appearance.black_ops mustEqual false
pc.appearance.jammered mustEqual false
pc.appearance.exosuit mustEqual ExoSuitType.MAX
pc.appearance.outfit_name mustEqual "Original District"
pc.appearance.outfit_logo mustEqual 23
pc.appearance.facingPitch mustEqual 0
pc.appearance.facingYawUpper mustEqual 180.0f
pc.appearance.lfs mustEqual false
pc.appearance.grenade_state mustEqual GrenadeState.None
pc.appearance.is_cloaking mustEqual false
pc.appearance.charging_pose mustEqual false
pc.appearance.on_zipline mustEqual false
pc.appearance.ribbons.upper mustEqual MeritCommendation.Jacking2
pc.appearance.ribbons.middle mustEqual MeritCommendation.ScavengerVS1
pc.appearance.ribbons.lower mustEqual MeritCommendation.AMSSupport4
pc.appearance.ribbons.tos mustEqual MeritCommendation.SixYearVS
pc.health mustEqual 0
pc.armor mustEqual 0
pc.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade
pc.command_rank mustEqual 2
pc.implant_effects.isDefined mustEqual false
pc.cosmetics.isDefined mustEqual true
pc.cosmetics.get.no_helmet mustEqual true
pc.cosmetics.get.beret mustEqual true
pc.cosmetics.get.sunglasses mustEqual true
pc.cosmetics.get.earpiece mustEqual true
pc.cosmetics.get.brimmed_cap mustEqual false
pc.inventory.isDefined mustEqual false
pc.drawn_slot mustEqual DrawnSlot.Pistol1
case _ =>
ko
}
}
"encode" in {
val obj = CharacterData(
CharacterAppearanceData(
PlacementData(
Vector3(3674.8438f, 2726.789f, 91.15625f),
Vector3(0f, 0f, 64.6875f),
Some(Vector3(1.4375f, -0.4375f, 0f))
),
BasicCharacterData(
"ScrawnyRonnie",
PlanetSideEmpire.TR,
CharacterGender.Male,
5,
5
),
3,
false,
false,
ExoSuitType.Reinforced,
"Black Beret Armoured Corps",
23,
false,
340.3125f, 0f,
false,
GrenadeState.None,
false, false, false,
RibbonBars(
MeritCommendation.MarkovVeteran,
MeritCommendation.HeavyInfantry4,
MeritCommendation.TankBuster7,
MeritCommendation.SixYearTR
)
),
255, 253,
UniformStyle.ThirdUpgrade,
5,
Some(ImplantEffects.NoEffects),
Some(Cosmetics(true, true, true, true, false)),
InventoryData(
InventoryItemData(ObjectClass.plasma_grenade, PlanetSideGUID(3662), 0, WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.bank, PlanetSideGUID(3908), 1, WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.mini_chaingun, PlanetSideGUID(4164), 2, WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.phoenix, PlanetSideGUID(3603), 3, WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.chainblade, PlanetSideGUID(4088), 4, WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, AmmoBoxData())) ::
Nil
),
DrawnSlot.Rifle1
)
val msg = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(3902), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
val pkt_bitv = pkt.toBitVector
val ori_bitv = string_character.toBitVector
pkt_bitv.take(452) mustEqual ori_bitv.take(452) //skip 126
pkt_bitv.drop(578).take(438) mustEqual ori_bitv.drop(578).take(438) //skip 2
pkt_bitv.drop(1018).take(17) mustEqual ori_bitv.drop(1018).take(17) //skip 11
pkt_bitv.drop(1046).take(147) mustEqual ori_bitv.drop(1046).take(147) //skip 3
pkt_bitv.drop(1196) mustEqual ori_bitv.drop(1196)
//TODO work on CharacterData to make this pass as a single stream
}
"encode (backpack)" in {
val obj = CharacterData(
CharacterAppearanceData(
PlacementData(4629.8906f, 6316.4453f, 54.734375f, 0f, 0f, 126.5625f),
BasicCharacterData(
"Angello",
PlanetSideEmpire.VS,
CharacterGender.Male,
10,
2
),
0,
false,
false,
ExoSuitType.MAX,
"Original District",
23,
true, //backpack
0f, 180.0f,
false,
GrenadeState.None,
false, false, false,
RibbonBars(
MeritCommendation.Jacking2,
MeritCommendation.ScavengerVS1,
MeritCommendation.AMSSupport4,
MeritCommendation.SixYearVS
)
),
0, 0,
UniformStyle.ThirdUpgrade,
2,
None,
Some(Cosmetics(true, true, true, true, false)),
None,
DrawnSlot.Pistol1
)
val msg = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(3380), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
val pkt_bitv = pkt.toBitVector
val ori_bitv = string_character_backpack.toBitVector
pkt_bitv.take(300) mustEqual ori_bitv.take(300) //skip 2
pkt_bitv.drop(302).take(14) mustEqual ori_bitv.drop(302).take(14) //skip 126
pkt_bitv.drop(442).take(305) mustEqual ori_bitv.drop(442).take(305) //skip 1
pkt_bitv.drop(748).take(9) mustEqual ori_bitv.drop(748).take(9) // skip 2
pkt_bitv.drop(759).take(157) mustEqual ori_bitv.drop(759).take(157) //skip 1
pkt_bitv.drop(917) mustEqual ori_bitv.drop(917)
//TODO work on CharacterData to make this pass as a single stream
}
}
}

View file

@ -0,0 +1,73 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import org.specs2.mutable._
import scodec.bits._
class CommandDetonaterDataTest extends Specification {
val string_detonater_held = hex"17 76000000 1A886A8421080400000000"
val string_detonater_dropped = hex"17 AF000000 EA8620ED1549B4B6A741500001B000000000"
"CommandDetonaterData" should {
"decode (held)" in {
PacketCoding.DecodePacket(string_detonater_held).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 118
cls mustEqual ObjectClass.command_detonater
guid mustEqual PlanetSideGUID(4162)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(4149)
parent.get.slot mustEqual 0
data.isDefined mustEqual true
data.get.isInstanceOf[CommandDetonaterData] mustEqual true
val cud = data.get.asInstanceOf[CommandDetonaterData]
cud.unk1 mustEqual 4
cud.unk2 mustEqual 0
case _ =>
ko
}
}
"decode (dropped)" in {
PacketCoding.DecodePacket(string_detonater_dropped).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 175
cls mustEqual ObjectClass.command_detonater
guid mustEqual PlanetSideGUID(3682)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DroppedItemData[_]] mustEqual true
val drop = data.get.asInstanceOf[DroppedItemData[_]]
drop.pos.coord.x mustEqual 4777.633f
drop.pos.coord.y mustEqual 5485.4062f
drop.pos.coord.z mustEqual 85.8125f
drop.pos.orient.x mustEqual 0f
drop.pos.orient.y mustEqual 0f
drop.pos.orient.z mustEqual 14.0625f
drop.obj.isInstanceOf[CommandDetonaterData] mustEqual true
case _ =>
ko
}
}
"encode (held)" in {
val obj = CommandDetonaterData(4)
val msg = ObjectCreateMessage(ObjectClass.command_detonater, PlanetSideGUID(4162), ObjectCreateMessageParent(PlanetSideGUID(4149), 0), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_detonater_held
}
"encode (dropped)" in {
val obj = DroppedItemData(
PlacementData(4777.633f, 5485.4062f, 85.8125f, 0f, 0f, 14.0625f),
CommandDetonaterData()
)
val msg = ObjectCreateMessage(ObjectClass.command_detonater, PlanetSideGUID(3682), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_detonater_dropped
}
}
}

View file

@ -0,0 +1,16 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
class CommonFieldDataTest extends Specification {
"CommonFieldData" should {
"construct" in {
CommonFieldData(PlacementData(0f, 0f, 0f), PlanetSideEmpire.NC, true, 5) mustEqual
CommonFieldData(PlacementData(0f, 0f, 0f), PlanetSideEmpire.NC, false, true, 5, false, PlanetSideGUID(0))
}
}
}

View file

@ -0,0 +1,80 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
import scodec.bits._
class CommonTerminalDataTest extends Specification {
val string_implant_interface = hex"17 6C000000 01014C93304818000000"
val string_order_terminala = hex"17 A5000000 B2AF30EACF1889F7A3D1200007D2000000"
"CommonTerminalData" should {
"decode (implant interface)" in {
PacketCoding.DecodePacket(string_implant_interface).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 108
cls mustEqual 0x199
guid mustEqual PlanetSideGUID(1075)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(514)
parent.get.slot mustEqual 1
data.isDefined mustEqual true
data.get.isInstanceOf[CommonTerminalData] mustEqual true
data.get.asInstanceOf[CommonTerminalData].faction mustEqual PlanetSideEmpire.VS
case _ =>
ko
}
}
"decode (order terminal a)" in {
PacketCoding.DecodePacket(string_order_terminala).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 165
cls mustEqual ObjectClass.order_terminala
guid mustEqual PlanetSideGUID(3827)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DroppedItemData[_]] mustEqual true
val drop = data.get.asInstanceOf[DroppedItemData[_]]
drop.pos.coord.x mustEqual 4579.3438f
drop.pos.coord.y mustEqual 5615.0703f
drop.pos.coord.z mustEqual 72.953125f
drop.pos.orient.x mustEqual 0f
drop.pos.orient.y mustEqual 0f
drop.pos.orient.z mustEqual 98.4375f
drop.obj.isInstanceOf[CommonTerminalData] mustEqual true
val term = drop.obj.asInstanceOf[CommonTerminalData]
term.faction mustEqual PlanetSideEmpire.NC
term.unk mustEqual 0
case _ =>
ko
}
}
"encode (implant interface)" in {
val obj = CommonTerminalData(PlanetSideEmpire.VS)
val msg = ObjectCreateMessage(0x199, PlanetSideGUID(1075), ObjectCreateMessageParent(PlanetSideGUID(514), 1), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_implant_interface
}
"encode (order terminal a)" in {
val obj = DroppedItemData(
PlacementData(4579.3438f, 5615.0703f, 72.953125f, 0f, 0f, 98.4375f),
CommonTerminalData(PlanetSideEmpire.NC)
)
val msg = ObjectCreateMessage(ObjectClass.order_terminala, PlanetSideGUID(3827), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_order_terminala
}
"InternalSlot" in {
CommonTerminalData(ObjectClass.order_terminala, PlanetSideGUID(1), 1, CommonTerminalData(PlanetSideEmpire.NC)) mustEqual
InternalSlot(ObjectClass.order_terminala, PlanetSideGUID(1), 1, CommonTerminalData(PlanetSideEmpire.NC))
}
}
}

View file

@ -0,0 +1,70 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import org.specs2.mutable._
import scodec.bits._
class LockerContainerDataTest extends Specification {
val string_locker_container = hex"17 AF010000 E414C0C00000000000000000000600000818829DC2E030000000202378620D80C00000378FA0FADC000006F1FC199D800000"
"LockerContainerData" should {
"decode" in {
PacketCoding.DecodePacket(string_locker_container).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 431
cls mustEqual ObjectClass.locker_container
guid mustEqual PlanetSideGUID(3148)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[LockerContainerData] mustEqual true
val locker = data.get.asInstanceOf[LockerContainerData]
val contents = locker.inventory.contents
contents.size mustEqual 3
//0
contents.head.objectClass mustEqual ObjectClass.nano_dispenser
contents.head.guid mustEqual PlanetSideGUID(2935)
contents.head.parentSlot mustEqual 0
contents.head.obj.isInstanceOf[WeaponData] mustEqual true
val dispenser = contents.head.obj.asInstanceOf[WeaponData]
dispenser.unk1 mustEqual 0x6
dispenser.unk2 mustEqual 0x0
dispenser.ammo.head.objectClass mustEqual ObjectClass.armor_canister
dispenser.ammo.head.guid mustEqual PlanetSideGUID(3426)
dispenser.ammo.head.parentSlot mustEqual 0
dispenser.ammo.head.obj.isInstanceOf[AmmoBoxData] mustEqual true
dispenser.ammo.head.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0
//1
contents(1).objectClass mustEqual ObjectClass.armor_canister
contents(1).guid mustEqual PlanetSideGUID(4090)
contents(1).parentSlot mustEqual 45
contents(1).obj.isInstanceOf[AmmoBoxData] mustEqual true
contents(1).obj.asInstanceOf[AmmoBoxData].unk mustEqual 0
//2
contents(2).objectClass mustEqual ObjectClass.armor_canister
contents(2).guid mustEqual PlanetSideGUID(3326)
contents(2).parentSlot mustEqual 78
contents(2).obj.isInstanceOf[AmmoBoxData] mustEqual true
contents(2).obj.asInstanceOf[AmmoBoxData].unk mustEqual 0
case _ =>
ko
}
}
"encode" in {
val obj = LockerContainerData(
InventoryData(
InventoryItemData(ObjectClass.nano_dispenser, PlanetSideGUID(2935), 0, WeaponData(0x6, 0x0, ObjectClass.armor_canister, PlanetSideGUID(3426), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.armor_canister, PlanetSideGUID(4090), 45, AmmoBoxData()) ::
InventoryItemData(ObjectClass.armor_canister, PlanetSideGUID(3326), 78, AmmoBoxData()) ::
Nil
)
)
val msg = ObjectCreateMessage(ObjectClass.locker_container, PlanetSideGUID(3148), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_locker_container
}
}
}

View file

@ -0,0 +1,110 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
import scodec.bits._
class OneMannedFieldTurretDataTest extends Specification {
val string_orion = hex"17 5E010000 D82640B 92F76 01D65 F611 00 00 5E 4400006304BFC1E4041826E1503900000010104CE704C06400000"
"OneMannedFieldTurretData" should {
"decode (orion)" in {
PacketCoding.DecodePacket(string_orion).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 350
cls mustEqual ObjectClass.portable_manned_turret_vs
guid mustEqual PlanetSideGUID(2916)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[OneMannedFieldTurretData] mustEqual true
val omft = data.get.asInstanceOf[OneMannedFieldTurretData]
omft.deploy.pos.coord.x mustEqual 3567.1406f
omft.deploy.pos.coord.y mustEqual 2988.0078f
omft.deploy.pos.coord.z mustEqual 71.84375f
omft.deploy.pos.orient.x mustEqual 0f
omft.deploy.pos.orient.y mustEqual 0f
omft.deploy.pos.orient.z mustEqual 185.625f
omft.deploy.faction mustEqual PlanetSideEmpire.VS
omft.deploy.unk mustEqual 2
omft.deploy.player_guid mustEqual PlanetSideGUID(2502)
omft.health mustEqual 255
omft.internals.isDefined mustEqual true
val internals = omft.internals.get
internals.objectClass mustEqual ObjectClass.energy_gun_vs
internals.guid mustEqual PlanetSideGUID(2615)
internals.parentSlot mustEqual 1
internals.obj.isInstanceOf[WeaponData] mustEqual true
val wep = internals.obj.asInstanceOf[WeaponData]
wep.unk1 mustEqual 0x6
wep.unk2 mustEqual 0x8
wep.fire_mode mustEqual 0
val ammo = wep.ammo.head
ammo.objectClass mustEqual ObjectClass.energy_gun_ammo
ammo.guid mustEqual PlanetSideGUID(2510)
ammo.parentSlot mustEqual 0
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 8
case _ =>
ko
}
}
"encode (orion)" in {
val obj = OneMannedFieldTurretData(
CommonFieldData(
PlacementData(3567.1406f, 2988.0078f, 71.84375f, 0f, 0f, 185.625f),
PlanetSideEmpire.VS, 2, PlanetSideGUID(2502)
),
255,
OneMannedFieldTurretData.orion(PlanetSideGUID(2615), 0x6, 0x8, PlanetSideGUID(2510), 8)
)
val msg = ObjectCreateMessage(ObjectClass.portable_manned_turret_vs, PlanetSideGUID(2916), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
val pkt_bitv = pkt.toBitVector
val ori_bitv = string_orion.toBitVector
pkt_bitv.take(189) mustEqual ori_bitv.take(189)
pkt_bitv.drop(200) mustEqual ori_bitv.drop(200)
//TODO work on OneMannedFieldTurretData to make this pass as a single stream
}
"avenger" in {
OneMannedFieldTurretData.avenger(PlanetSideGUID(1), 2, 3, PlanetSideGUID(4), 5) mustEqual
InternalSlot(ObjectClass.energy_gun_tr, PlanetSideGUID(1), 1,
WeaponData(2, 3, ObjectClass.energy_gun_ammo, PlanetSideGUID(4), 0,
AmmoBoxData(5)
)
)
}
"generic" in {
OneMannedFieldTurretData.generic(PlanetSideGUID(1), 2, 3, PlanetSideGUID(4), 5) mustEqual
InternalSlot(ObjectClass.energy_gun, PlanetSideGUID(1), 1,
WeaponData(2, 3, ObjectClass.energy_gun_ammo, PlanetSideGUID(4), 0,
AmmoBoxData(5)
)
)
}
"orion" in {
OneMannedFieldTurretData.orion(PlanetSideGUID(1), 2, 3, PlanetSideGUID(4), 5) mustEqual
InternalSlot(ObjectClass.energy_gun_vs, PlanetSideGUID(1), 1,
WeaponData(2, 3, ObjectClass.energy_gun_ammo, PlanetSideGUID(4), 0,
AmmoBoxData(5)
)
)
}
"osprey" in {
OneMannedFieldTurretData.osprey(PlanetSideGUID(1), 2, 3, PlanetSideGUID(4), 5) mustEqual
InternalSlot(ObjectClass.energy_gun_nc, PlanetSideGUID(1), 1,
WeaponData(2, 3, ObjectClass.energy_gun_ammo, PlanetSideGUID(4), 0,
AmmoBoxData(5)
)
)
}
}
}

View file

@ -0,0 +1,78 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import org.specs2.mutable._
import scodec.bits._
class REKDataTest extends Specification {
val string_rek_held = hex"17 86000000 27086C2350F800800000000000"
val string_rek_dropped = hex"17 BF000000 EC20311 85219 7AC1A 2D12 00 00 4E 4000000001800"
"REKData" should {
"decode (held)" in {
PacketCoding.DecodePacket(string_rek_held).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 134
cls mustEqual ObjectClass.remote_electronics_kit
guid mustEqual PlanetSideGUID(3893)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(4174)
parent.get.slot mustEqual 0
data.isDefined mustEqual true
data.get.isInstanceOf[REKData] mustEqual true
val rek = data.get.asInstanceOf[REKData]
rek.unk1 mustEqual 0
rek.unk2 mustEqual 8
rek.unk3 mustEqual 0
case _ =>
ko
}
}
"decode (dropped)" in {
PacketCoding.DecodePacket(string_rek_dropped).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 191
cls mustEqual ObjectClass.remote_electronics_kit
guid mustEqual PlanetSideGUID(4355)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DroppedItemData[_]] mustEqual true
val dropped = data.get.asInstanceOf[DroppedItemData[_]]
dropped.pos.coord.x mustEqual 4675.039f
dropped.pos.coord.y mustEqual 5506.953f
dropped.pos.coord.z mustEqual 72.703125f
dropped.pos.orient.x mustEqual 0f
dropped.pos.orient.y mustEqual 0f
dropped.pos.orient.z mustEqual 230.625f
dropped.obj.isInstanceOf[REKData] mustEqual true
val rek = dropped.obj.asInstanceOf[REKData]
rek.unk1 mustEqual 8
rek.unk2 mustEqual 0
rek.unk3 mustEqual 3
case _ =>
ko
}
}
"encode (held)" in {
val obj = REKData(0, 8)
val msg = ObjectCreateMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(3893), ObjectCreateMessageParent(PlanetSideGUID(4174), 0), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_rek_held
}
"encode (dropped)" in {
val obj = DroppedItemData(
PlacementData(4675.039f, 5506.953f, 72.703125f, 0f, 0f, 230.625f),
REKData(8, 0, 3)
)
val msg = ObjectCreateMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(4355), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_rek_dropped
}
}
}

View file

@ -0,0 +1,36 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.game.objectcreate._
import net.psforever.types.MeritCommendation
import org.specs2.mutable._
class RibbonBarsTest extends Specification {
"RibbonBars" should {
"construct" in {
RibbonBars()
ok
}
"construct (custom)" in {
RibbonBars(
MeritCommendation.MarkovVeteran,
MeritCommendation.HeavyInfantry4,
MeritCommendation.TankBuster7,
MeritCommendation.SixYearTR
)
ok
}
"size" in {
RibbonBars().bitsize mustEqual 128L
RibbonBars(
MeritCommendation.MarkovVeteran,
MeritCommendation.HeavyInfantry4,
MeritCommendation.TankBuster7,
MeritCommendation.SixYearTR
).bitsize mustEqual 128L
}
}
}

View file

@ -0,0 +1,50 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
import scodec.bits._
class SmallDeployableDataTest extends Specification {
val string_boomer = hex"17 A5000000 CA0000F1630938D5A8F1400003F0031100"
"SmallDeployableData" should {
"decode (boomer)" in {
PacketCoding.DecodePacket(string_boomer).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 165
cls mustEqual ObjectClass.boomer
guid mustEqual PlanetSideGUID(3840)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[SmallDeployableData] mustEqual true
val boomer = data.get.asInstanceOf[SmallDeployableData]
boomer.deploy.pos.coord.x mustEqual 4704.172f
boomer.deploy.pos.coord.y mustEqual 5546.4375f
boomer.deploy.pos.coord.z mustEqual 82.234375f
boomer.deploy.pos.orient.x mustEqual 0f
boomer.deploy.pos.orient.y mustEqual 0f
boomer.deploy.pos.orient.z mustEqual 272.8125f
boomer.deploy.unk mustEqual 0
boomer.deploy.player_guid mustEqual PlanetSideGUID(4145)
case _ =>
ko
}
}
"encode (boomer)" in {
val obj = SmallDeployableData(
CommonFieldData(
PlacementData(4704.172f, 5546.4375f, 82.234375f, 0f, 0f, 272.8125f),
PlanetSideEmpire.TR, 0, PlanetSideGUID(4145)
)
)
val msg = ObjectCreateMessage(ObjectClass.boomer, PlanetSideGUID(3840), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_boomer
}
}
}

View file

@ -0,0 +1,119 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
import scodec.bits._
class SmallTurretDataTest extends Specification {
val string_spitfire_short = hex"17 BB000000 9D37010 E4F08 6AFCA 0312 00 7F 42 2C1F0F0000F00"
val string_spitfire = hex"17 4F010000 9D3A910 D1D78 AE3FC 9111 00 00 69 4488107F80F2021DBF80B80C80000008086EDB83A03200000"
"SmallTurretData" should {
"decode (spitfire, short)" in {
PacketCoding.DecodePacket(string_spitfire_short).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 187
cls mustEqual ObjectClass.spitfire_turret
guid mustEqual PlanetSideGUID(4208)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[SmallTurretData] mustEqual true
val turret = data.get.asInstanceOf[SmallTurretData]
turret.deploy.pos.coord.x mustEqual 4577.7812f
turret.deploy.pos.coord.y mustEqual 5624.828f
turret.deploy.pos.coord.z mustEqual 72.046875f
turret.deploy.pos.orient.x mustEqual 0f
turret.deploy.pos.orient.y mustEqual 2.8125f
turret.deploy.pos.orient.z mustEqual 264.375f
turret.deploy.faction mustEqual PlanetSideEmpire.NC
turret.deploy.destroyed mustEqual true
turret.deploy.unk mustEqual 2
turret.deploy.player_guid mustEqual PlanetSideGUID(3871)
turret.health mustEqual 0
turret.internals.isDefined mustEqual false
case _ =>
ko
}
}
"decode (spitfire)" in {
PacketCoding.DecodePacket(string_spitfire).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 335
cls mustEqual ObjectClass.spitfire_turret
guid mustEqual PlanetSideGUID(4265)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[SmallTurretData] mustEqual true
val turret = data.get.asInstanceOf[SmallTurretData]
turret.deploy.pos.coord.x mustEqual 4527.633f
turret.deploy.pos.coord.y mustEqual 6271.3594f
turret.deploy.pos.coord.z mustEqual 70.265625f
turret.deploy.pos.orient.x mustEqual 0f
turret.deploy.pos.orient.y mustEqual 0f
turret.deploy.pos.orient.z mustEqual 154.6875f
turret.deploy.faction mustEqual PlanetSideEmpire.VS
turret.deploy.unk mustEqual 2
turret.deploy.player_guid mustEqual PlanetSideGUID(4232)
turret.health mustEqual 255
turret.internals.isDefined mustEqual true
val internals = turret.internals.get
internals.objectClass mustEqual ObjectClass.spitfire_weapon
internals.guid mustEqual PlanetSideGUID(3064)
internals.parentSlot mustEqual 0
internals.obj.isInstanceOf[WeaponData] mustEqual true
val wep = internals.obj.asInstanceOf[WeaponData]
wep.unk1 mustEqual 0x6
wep.unk2 mustEqual 0x8
wep.fire_mode mustEqual 0
val ammo = wep.ammo.head
ammo.objectClass mustEqual ObjectClass.spitfire_ammo
ammo.guid mustEqual PlanetSideGUID(3694)
ammo.parentSlot mustEqual 0
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 8
case _ =>
ko
}
}
"encode (spitfire, short)" in {
val obj = SmallTurretData(
CommonFieldData(
PlacementData(4577.7812f, 5624.828f, 72.046875f, 0f, 2.8125f, 264.375f),
PlanetSideEmpire.NC, true, 2, PlanetSideGUID(3871)
),
255 //sets to 0
)
val msg = ObjectCreateMessage(ObjectClass.spitfire_turret, PlanetSideGUID(4208), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
val pkt_bitv = pkt.toBitVector
val ori_bitv = string_spitfire_short.toBitVector
pkt_bitv.take(173) mustEqual ori_bitv.take(173)
pkt_bitv.drop(185) mustEqual ori_bitv.drop(185)
//TODO work on SmallTurretData to make this pass as a single stream
}
"encode (spitfire)" in {
val obj = SmallTurretData(
CommonFieldData(
PlacementData(4527.633f, 6271.3594f, 70.265625f, 0f, 0f, 154.6875f),
PlanetSideEmpire.VS, 2, PlanetSideGUID(4232)
),
255,
SmallTurretData.spitfire(PlanetSideGUID(3064), 0x6, 0x8, PlanetSideGUID(3694), 8)
)
val msg = ObjectCreateMessage(ObjectClass.spitfire_turret, PlanetSideGUID(4265), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
val pkt_bitv = pkt.toBitVector
val ori_bitv = string_spitfire.toBitVector
pkt_bitv.take(173) mustEqual ori_bitv.take(173)
pkt_bitv.drop(185) mustEqual ori_bitv.drop(185)
//TODO work on SmallTurretData to make this pass as a single stream
}
}
}

View file

@ -0,0 +1,57 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
import scodec.bits._
class TRAPDataTest extends Specification {
val string_trap = hex"17 BB000000 A8B630A 39FA6 FD666 801C 00 00 00 44C6097F80F00"
"TRAPData" should {
"decode" in {
PacketCoding.DecodePacket(string_trap).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 187
cls mustEqual ObjectClass.tank_traps
guid mustEqual PlanetSideGUID(2659)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[TRAPData] mustEqual true
val trap = data.get.asInstanceOf[TRAPData]
trap.deploy.pos.coord.x mustEqual 3572.4453f
trap.deploy.pos.coord.y mustEqual 3277.9766f
trap.deploy.pos.coord.z mustEqual 114.0f
trap.deploy.pos.orient.x mustEqual 0f
trap.deploy.pos.orient.y mustEqual 0f
trap.deploy.pos.orient.z mustEqual 90.0f
trap.deploy.faction mustEqual PlanetSideEmpire.VS
trap.deploy.unk mustEqual 2
trap.health mustEqual 255
trap.deploy.player_guid mustEqual PlanetSideGUID(2502)
case _ =>
ko
}
}
"encode" in {
val obj = TRAPData(
CommonFieldData(
PlacementData(3572.4453f, 3277.9766f, 114.0f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 2, PlanetSideGUID(2502)
),
255
)
val msg = ObjectCreateMessage(ObjectClass.tank_traps, PlanetSideGUID(2659), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
val pkt_bitv = pkt.toBitVector
val ori_bitv = string_trap.toBitVector
pkt_bitv.take(173) mustEqual ori_bitv.take(173)
pkt_bitv.drop(185) mustEqual ori_bitv.drop(185)
//TODO work on TRAPData to make this pass as a single stream
}
}
}

View file

@ -0,0 +1,70 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate.{ObjectClass, PlacementData, TrackedProjectileData}
import org.specs2.mutable._
import scodec.bits._
class TrackedProjectileDataTest extends Specification {
val string_striker_projectile = hex"17 C5000000 A4B 009D 4C129 0CB0A 9814 00 F5 E3 040000666686400"
"TrackedProjectileData" should {
"decode (striker projectile)" in {
PacketCoding.DecodePacket(string_striker_projectile).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 197
cls mustEqual ObjectClass.striker_missile_targeting_projectile
guid mustEqual PlanetSideGUID(40192)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[TrackedProjectileData] mustEqual true
val projectile = data.get.asInstanceOf[TrackedProjectileData]
projectile.pos.coord.x mustEqual 4644.5938f
projectile.pos.coord.y mustEqual 5472.0938f
projectile.pos.coord.z mustEqual 82.375f
projectile.pos.orient.x mustEqual 0f
projectile.pos.orient.y mustEqual 30.9375f
projectile.pos.orient.z mustEqual 171.5625f
projectile.unk1 mustEqual 0
projectile.unk2 mustEqual TrackedProjectileData.striker_missile_targetting_projectile_data
case _ =>
ko
}
}
"encode (striker projectile)" in {
val obj = TrackedProjectileData.striker(
PlacementData(4644.5938f, 5472.0938f, 82.375f, 0f, 30.9375f, 171.5625f),
0
)
val msg = ObjectCreateMessage(ObjectClass.striker_missile_targeting_projectile, PlanetSideGUID(40192), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt.toBitVector.take(132) mustEqual string_striker_projectile.toBitVector.take(132)
pkt.toBitVector.drop(133).take(7) mustEqual string_striker_projectile.toBitVector.drop(133).take(7)
pkt.toBitVector.drop(141) mustEqual string_striker_projectile.toBitVector.drop(141)
}
"hunter_seeker" in {
TrackedProjectileData.hunter_seeker(PlacementData(0f, 0f, 0f), 0) mustEqual
TrackedProjectileData(PlacementData(0f, 0f, 0f), 0, TrackedProjectileData.hunter_seeker_missile_projectile_data)
}
"oicw" in {
TrackedProjectileData.oicw(PlacementData(0f, 0f, 0f), 0) mustEqual
TrackedProjectileData(PlacementData(0f, 0f, 0f), 0, TrackedProjectileData.oicw_projectile_data)
}
"starfire" in {
TrackedProjectileData.starfire(PlacementData(0f, 0f, 0f), 0) mustEqual
TrackedProjectileData(PlacementData(0f, 0f, 0f), 0, TrackedProjectileData.starfire_projectile_data)
}
"striker" in {
TrackedProjectileData.striker(PlacementData(0f, 0f, 0f), 0) mustEqual
TrackedProjectileData(PlacementData(0f, 0f, 0f), 0, TrackedProjectileData.striker_missile_targetting_projectile_data)
}
}
}

View file

@ -0,0 +1,192 @@
// Copyright (c) 2017 PSForever
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import org.specs2.mutable._
import scodec.bits._
class WeaponDataTest extends Specification {
val string_lasher_held = hex"17 BB000000 1688569D90B83 880000008082077036032000000"
val string_punisher_held = hex"17 F6000000 0A06612331083 88000000810381383E03200003793287C0E400000"
val string_lasher_dropped = hex"17 F4000000 D69020C 99299 85D0A 5F10 00 00 20 400000004041038819018000000"
val string_punisher_dropped = hex"17 2F010000 E12A20B 915A9 28C9A 1412 00 00 33 200000004081C1901B01800001BCB5C2E07000000"
"WeaponData" should {
"decode (lasher, held)" in {
PacketCoding.DecodePacket(string_lasher_held).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 187
cls mustEqual ObjectClass.lasher
guid mustEqual PlanetSideGUID(3033)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(4141)
parent.get.slot mustEqual 3
data.isDefined mustEqual true
data.get.isInstanceOf[WeaponData] mustEqual true
val wep = data.get.asInstanceOf[WeaponData]
wep.unk1 mustEqual 4
wep.unk2 mustEqual 8
wep.fire_mode mustEqual 0
wep.ammo.head.objectClass mustEqual ObjectClass.energy_cell
wep.ammo.head.guid mustEqual PlanetSideGUID(3548)
wep.ammo.head.parentSlot mustEqual 0
wep.ammo.head.obj.isInstanceOf[AmmoBoxData] mustEqual true
val ammo = wep.ammo.head.obj.asInstanceOf[AmmoBoxData]
ammo.unk mustEqual 8
case _ =>
ko
}
}
"decode (punisher, held)" in {
PacketCoding.DecodePacket(string_punisher_held).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 246
cls mustEqual ObjectClass.punisher
guid mustEqual PlanetSideGUID(4147)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(3092)
parent.get.slot mustEqual 3
data.isDefined mustEqual true
data.get.isInstanceOf[WeaponData] mustEqual true
val wep = data.get.asInstanceOf[WeaponData]
wep.unk1 mustEqual 4
wep.unk2 mustEqual 8
wep.fire_mode mustEqual 0
val ammo = wep.ammo
ammo.size mustEqual 2
//0
ammo.head.objectClass mustEqual ObjectClass.bullet_9mm
ammo.head.guid mustEqual PlanetSideGUID(3918)
ammo.head.parentSlot mustEqual 0
ammo.head.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.head.obj.asInstanceOf[AmmoBoxData].unk mustEqual 8
//1
ammo(1).objectClass mustEqual ObjectClass.rocket
ammo(1).guid mustEqual PlanetSideGUID(3941)
ammo(1).parentSlot mustEqual 1
ammo(1).obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo(1).obj.asInstanceOf[AmmoBoxData].unk mustEqual 8
case _ =>
ko
}
}
"decode (lasher, dropped)" in {
PacketCoding.DecodePacket(string_lasher_dropped).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 244
cls mustEqual ObjectClass.lasher
guid mustEqual PlanetSideGUID(3074)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DroppedItemData[_]] mustEqual true
val drop = data.get.asInstanceOf[DroppedItemData[_]]
drop.pos.coord.x mustEqual 4691.1953f
drop.pos.coord.y mustEqual 5537.039f
drop.pos.coord.z mustEqual 65.484375f
drop.pos.orient.x mustEqual 0f
drop.pos.orient.y mustEqual 0f
drop.pos.orient.z mustEqual 0f
drop.obj.isInstanceOf[WeaponData] mustEqual true
val wep = drop.obj.asInstanceOf[WeaponData]
wep.unk1 mustEqual 4
wep.unk2 mustEqual 0
wep.fire_mode mustEqual 0
wep.ammo.head.objectClass mustEqual ObjectClass.energy_cell
wep.ammo.head.guid mustEqual PlanetSideGUID(3268)
wep.ammo.head.parentSlot mustEqual 0
wep.ammo.head.obj.isInstanceOf[AmmoBoxData] mustEqual true
val ammo = wep.ammo.head.obj.asInstanceOf[AmmoBoxData]
ammo.unk mustEqual 0
case _ =>
ko
}
}
"decode (punisher, dropped)" in {
PacketCoding.DecodePacket(string_punisher_dropped).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 303
cls mustEqual ObjectClass.punisher
guid mustEqual PlanetSideGUID(2978)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DroppedItemData[_]] mustEqual true
val drop = data.get.asInstanceOf[DroppedItemData[_]]
drop.pos.coord.x mustEqual 4789.133f
drop.pos.coord.y mustEqual 5522.3125f
drop.pos.coord.z mustEqual 72.3125f
drop.pos.orient.x mustEqual 0f
drop.pos.orient.y mustEqual 0f
drop.pos.orient.z mustEqual 306.5625f
drop.obj.isInstanceOf[WeaponData] mustEqual true
val wep = drop.obj.asInstanceOf[WeaponData]
wep.unk1 mustEqual 2
wep.unk2 mustEqual 0
wep.fire_mode mustEqual 0
val ammo = wep.ammo
ammo.size mustEqual 2
//0
ammo.head.objectClass mustEqual ObjectClass.bullet_9mm
ammo.head.guid mustEqual PlanetSideGUID(3528)
ammo.head.parentSlot mustEqual 0
ammo.head.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.head.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0
//1
ammo(1).objectClass mustEqual ObjectClass.rocket
ammo(1).guid mustEqual PlanetSideGUID(3031)
ammo(1).parentSlot mustEqual 1
ammo(1).obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo(1).obj.asInstanceOf[AmmoBoxData].unk mustEqual 0
case _ =>
ko
}
}
"encode (lasher, held)" in {
val obj = WeaponData(4, 8, ObjectClass.energy_cell, PlanetSideGUID(3548), 0, AmmoBoxData(8))
val msg = ObjectCreateMessage(ObjectClass.lasher, PlanetSideGUID(3033), ObjectCreateMessageParent(PlanetSideGUID(4141), 3), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_lasher_held
}
"encode (punisher, held)" in {
val obj =
WeaponData(4, 8, 0,
AmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(3918), 0, AmmoBoxData(8)) ::
AmmoBoxData(ObjectClass.rocket, PlanetSideGUID(3941), 1, AmmoBoxData(8)) ::
Nil
)(2)
val msg = ObjectCreateMessage(ObjectClass.punisher, PlanetSideGUID(4147), ObjectCreateMessageParent(PlanetSideGUID(3092), 3), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_punisher_held
}
"encode (lasher, dropped)" in {
val obj = DroppedItemData(
PlacementData(4691.1953f, 5537.039f, 65.484375f, 0.0f, 0.0f, 0.0f),
WeaponData(4, 0, ObjectClass.energy_cell, PlanetSideGUID(3268), 0, AmmoBoxData())
)
val msg = ObjectCreateMessage(ObjectClass.lasher, PlanetSideGUID(3074), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_lasher_dropped
}
"encode (punisher, dropped)" in {
val obj = DroppedItemData(
PlacementData(4789.133f, 5522.3125f, 72.3125f, 0f, 0f, 306.5625f),
WeaponData(2, 0, 0,
AmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(3528), 0, AmmoBoxData()) ::
AmmoBoxData(ObjectClass.rocket, PlanetSideGUID(3031), 1, AmmoBoxData()) ::
Nil
)(2)
)
val msg = ObjectCreateMessage(ObjectClass.punisher, PlanetSideGUID(2978), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_punisher_dropped
}
}
}

View file

@ -0,0 +1,39 @@
// Copyright (c) 2017 PSForever
package game.objectcreatedetailed
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateDetailedMessage, _}
import net.psforever.packet.game.objectcreate._
import scodec.bits._
class DetailedACEDataTest extends Specification {
val string_ace = hex"18 87000000 1006 100 C70B 80 8800000200008"
"DetailedACEData" should {
"decode" in {
PacketCoding.DecodePacket(string_ace).require match {
case ObjectCreateDetailedMessage(len, cls, guid, parent, data) =>
len mustEqual 135
cls mustEqual ObjectClass.ace
guid mustEqual PlanetSideGUID(3015)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(3104)
parent.get.slot mustEqual 0
data.isDefined mustEqual true
data.get.isInstanceOf[DetailedACEData] mustEqual true
data.get.asInstanceOf[DetailedACEData].unk mustEqual 8
case _ =>
ko
}
}
"encode" in {
val obj = DetailedACEData(8)
val msg = ObjectCreateDetailedMessage(ObjectClass.ace, PlanetSideGUID(3015), ObjectCreateMessageParent(PlanetSideGUID(3104), 0), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ace
}
}
}

View file

@ -0,0 +1,38 @@
// Copyright (c) 2017 PSForever
package game.objectcreatedetailed
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateDetailedMessage, _}
import net.psforever.packet.game.objectcreate._
import scodec.bits._
class DetailedAmmoBoxDataTest extends Specification {
val string_9mm = hex"18 7C000000 2580 0E0 0005 A1 C8000064000"
"DetailedAmmoBoxData" should {
"decode (9mm)" in {
PacketCoding.DecodePacket(string_9mm).require match {
case ObjectCreateDetailedMessage(len, cls, guid, parent, data) =>
len mustEqual 124
cls mustEqual ObjectClass.bullet_9mm
guid mustEqual PlanetSideGUID(1280)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(75)
parent.get.slot mustEqual 33
data.isDefined mustEqual true
data.get.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50
case _ =>
ko
}
}
"encode (9mm)" in {
val obj = DetailedAmmoBoxData(8, 50)
val msg = ObjectCreateDetailedMessage(ObjectClass.bullet_9mm, PlanetSideGUID(1280), ObjectCreateMessageParent(PlanetSideGUID(75), 33), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_9mm
}
}
}

View file

@ -0,0 +1,38 @@
// Copyright (c) 2017 PSForever
package game.objectcreatedetailed
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateDetailedMessage, _}
import net.psforever.packet.game.objectcreate._
import scodec.bits._
class DetailedBoomerTriggerDataTest extends Specification {
val string_boomer_trigger = hex"18 87000000 6304CA8760B 80 C800000200008"
"DetailedBoomerTriggerData" should {
"decode" in {
PacketCoding.DecodePacket(string_boomer_trigger).require match {
case ObjectCreateDetailedMessage(len, cls, guid, parent, data) =>
len mustEqual 135
cls mustEqual ObjectClass.boomer_trigger
guid mustEqual PlanetSideGUID(2934)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(2502)
parent.get.slot mustEqual 0
data.isDefined mustEqual true
data.get.isInstanceOf[DetailedBoomerTriggerData] mustEqual true
case _ =>
ko
}
}
"encode" in {
val obj = DetailedBoomerTriggerData()
val msg = ObjectCreateDetailedMessage(ObjectClass.boomer_trigger, PlanetSideGUID(2934), ObjectCreateMessageParent(PlanetSideGUID(2502), 0), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_boomer_trigger
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,37 @@
// Copyright (c) 2017 PSForever
package game.objectcreatedetailed
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateDetailedMessage, _}
import net.psforever.packet.game.objectcreate._
import scodec.bits._
class DetailedCommandDetonaterDataTest extends Specification {
val string_detonater = hex"18 87000000 6506 EA8 7420 80 8000000200008"
"DetailedCommandDetonaterData" should {
"decode" in {
PacketCoding.DecodePacket(string_detonater).require match {
case ObjectCreateDetailedMessage(len, cls, guid, parent, data) =>
len mustEqual 135
cls mustEqual ObjectClass.command_detonater
guid mustEqual PlanetSideGUID(8308)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(3530)
parent.get.slot mustEqual 0
data.isDefined mustEqual true
data.get.isInstanceOf[DetailedCommandDetonaterData] mustEqual true
case _ =>
ko
}
}
"encode" in {
val obj = DetailedCommandDetonaterData()
val msg = ObjectCreateDetailedMessage(ObjectClass.command_detonater, PlanetSideGUID(8308), ObjectCreateMessageParent(PlanetSideGUID(3530), 0), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_detonater
}
}
}

View file

@ -0,0 +1,39 @@
// Copyright (c) 2017 PSForever
package game.objectcreatedetailed
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateDetailedMessage, _}
import net.psforever.packet.game.objectcreate._
import scodec.bits._
class DetailedREKDataTest extends Specification {
val string_rek = hex"18 97000000 2580 6C2 9F05 81 48000002000080000"
"DetailedREKData" should {
"decode" in {
PacketCoding.DecodePacket(string_rek).require match {
case ObjectCreateDetailedMessage(len, cls, guid, parent, data) =>
len mustEqual 151
cls mustEqual ObjectClass.remote_electronics_kit
guid mustEqual PlanetSideGUID(1439)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(75)
parent.get.slot mustEqual 1
data.isDefined mustEqual true
data.get.asInstanceOf[DetailedREKData].unk1 mustEqual 4
data.get.asInstanceOf[DetailedREKData].unk2 mustEqual 0
case _ =>
ko
}
}
"encode" in {
val obj = DetailedREKData(4)
val msg = ObjectCreateDetailedMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(1439), ObjectCreateMessageParent(PlanetSideGUID(75), 1), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_rek
}
}
}

View file

@ -0,0 +1,86 @@
// Copyright (c) 2017 PSForever
package game.objectcreatedetailed
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateDetailedMessage, _}
import net.psforever.packet.game.objectcreate._
import scodec.bits._
class DetailedWeaponDataTest extends Specification {
val string_gauss = hex"18 DC000000 2580 2C9 B905 82 480000020000C04 1C00C0B0190000078000"
val string_punisher = hex"18 27010000 2580 612 a706 82 080000020000c08 1c13a0d01900000780 13a4701a072000000800"
"DetailedWeaponData" should {
"decode (gauss)" in {
PacketCoding.DecodePacket(string_gauss).require match {
case ObjectCreateDetailedMessage(len, cls, guid, parent, data) =>
len mustEqual 220
cls mustEqual ObjectClass.gauss
guid mustEqual PlanetSideGUID(1465)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(75)
parent.get.slot mustEqual 2
data.isDefined mustEqual true
val obj_wep = data.get.asInstanceOf[DetailedWeaponData]
obj_wep.unk1 mustEqual 2
obj_wep.unk2 mustEqual 8
val obj_ammo = obj_wep.ammo
obj_ammo.head.objectClass mustEqual 28
obj_ammo.head.guid mustEqual PlanetSideGUID(1286)
obj_ammo.head.parentSlot mustEqual 0
obj_ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 30
case _ =>
ko
}
}
"decode (punisher)" in {
PacketCoding.DecodePacket(string_punisher).require match {
case ObjectCreateDetailedMessage(len, cls, guid, parent, data) =>
len mustEqual 295
cls mustEqual ObjectClass.punisher
guid mustEqual PlanetSideGUID(1703)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(75)
parent.get.slot mustEqual 2
data.isDefined mustEqual true
val obj_wep = data.get.asInstanceOf[DetailedWeaponData]
obj_wep.unk1 mustEqual 0
obj_wep.unk2 mustEqual 8
val obj_ammo = obj_wep.ammo
obj_ammo.size mustEqual 2
obj_ammo.head.objectClass mustEqual ObjectClass.bullet_9mm
obj_ammo.head.guid mustEqual PlanetSideGUID(1693)
obj_ammo.head.parentSlot mustEqual 0
obj_ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 30
obj_ammo(1).objectClass mustEqual ObjectClass.jammer_cartridge
obj_ammo(1).guid mustEqual PlanetSideGUID(1564)
obj_ammo(1).parentSlot mustEqual 1
obj_ammo(1).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 1
case _ =>
ko
}
}
"encode (gauss)" in {
val obj = DetailedWeaponData(2, 8, ObjectClass.bullet_9mm, PlanetSideGUID(1286), 0, DetailedAmmoBoxData(8, 30))
val msg = ObjectCreateDetailedMessage(ObjectClass.gauss, PlanetSideGUID(1465), ObjectCreateMessageParent(PlanetSideGUID(75), 2), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_gauss
}
"encode (punisher)" in {
val obj = DetailedWeaponData(0, 8,
DetailedAmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(1693), 0, DetailedAmmoBoxData(8, 30)) ::
DetailedAmmoBoxData(ObjectClass.jammer_cartridge, PlanetSideGUID(1564), 1, DetailedAmmoBoxData(8, 1)) ::
Nil
)(2)
val msg = ObjectCreateDetailedMessage(ObjectClass.punisher, PlanetSideGUID(1703), ObjectCreateMessageParent(PlanetSideGUID(75), 2), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_punisher
}
}
}

View file

@ -0,0 +1,44 @@
// Copyright (c) 2017 PSForever
package game.objectcreatevehicle
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types._
import org.specs2.mutable._
import scodec.bits._
class DestroyedVehiclesTest extends Specification {
val string_ams_destroyed = hex"17 8D000000 978 3D10 002D765535CA16000000 0"
"Destroyed vehicles" should {
"decode (ams, destroyed)" in {
PacketCoding.DecodePacket(string_ams_destroyed).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 141L
cls mustEqual ObjectClass.ams_destroyed
guid mustEqual PlanetSideGUID(4157)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DestroyedVehicleData] mustEqual true
val dams = data.get.asInstanceOf[DestroyedVehicleData]
dams.pos.coord.x mustEqual 3674.0f
dams.pos.coord.y mustEqual 2726.789f
dams.pos.coord.z mustEqual 91.15625f
dams.pos.orient.x mustEqual 0f
dams.pos.orient.y mustEqual 0f
dams.pos.orient.z mustEqual 90.0f
case _ =>
ko
}
}
"encode (ams, destroyed)" in {
val obj = DestroyedVehicleData(PlacementData(3674.0f, 2726.789f, 91.15625f, 0f, 0f, 90.0f))
val msg = ObjectCreateMessage(ObjectClass.ams_destroyed, PlanetSideGUID(4157), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ams_destroyed
}
}
}

View file

@ -0,0 +1,113 @@
// Copyright (c) 2017 PSForever
package game.objectcreatevehicle
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types._
import org.specs2.mutable._
import scodec.bits._
class NonstandardVehiclesTest extends Specification {
val string_droppod = hex"17 C1000000 8110B0E00FA9000ACFFFF000000 4400007F83C0900"
val string_orbital_shuttle_1 = hex"17 82000000 0901B026904838000001FE0700"
val string_orbital_shuttle_2 = hex"17 C3000000 B02670402F5AA14F88C210000604000007F8FF03C0"
"Nonstandard vehicles" should {
"decode (droppod)" in {
PacketCoding.DecodePacket(string_droppod).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 193L
cls mustEqual ObjectClass.droppod
guid mustEqual PlanetSideGUID(3595)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[DroppodData] mustEqual true
val droppod = data.get.asInstanceOf[DroppodData]
droppod.basic.pos.coord.x mustEqual 5108.0f
droppod.basic.pos.coord.y mustEqual 6164.0f
droppod.basic.pos.coord.z mustEqual 1023.9844f
droppod.basic.pos.orient.x mustEqual 0f
droppod.basic.pos.orient.y mustEqual 0f
droppod.basic.pos.orient.z mustEqual 90.0f
droppod.basic.unk mustEqual 2
droppod.basic.player_guid mustEqual PlanetSideGUID(0)
droppod.burn mustEqual false
droppod.health mustEqual 255
case _ =>
ko
}
}
"decode (shuttle 1)" in {
PacketCoding.DecodePacket(string_orbital_shuttle_1).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 130
cls mustEqual ObjectClass.orbital_shuttle
guid mustEqual PlanetSideGUID(1129)
parent.isDefined mustEqual true
parent.get.guid mustEqual PlanetSideGUID(786)
parent.get.slot mustEqual 3
data.isDefined mustEqual true
data.get.isInstanceOf[OrbitalShuttleData] mustEqual true
data.get.asInstanceOf[OrbitalShuttleData].faction mustEqual PlanetSideEmpire.VS
data.get.asInstanceOf[OrbitalShuttleData].pos.isDefined mustEqual false
case _ =>
ko
}
}
"decode (shuttle 2)" in {
PacketCoding.DecodePacket(string_orbital_shuttle_2).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 195
cls mustEqual ObjectClass.orbital_shuttle
guid mustEqual PlanetSideGUID(1127)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[OrbitalShuttleData] mustEqual true
val shuttle = data.get.asInstanceOf[OrbitalShuttleData]
shuttle.faction mustEqual PlanetSideEmpire.VS
shuttle.pos.isDefined mustEqual true
shuttle.pos.get.coord.x mustEqual 5610.0156f
shuttle.pos.get.coord.y mustEqual 4255.258f
shuttle.pos.get.coord.z mustEqual 134.1875f
shuttle.pos.get.orient.x mustEqual 0f
shuttle.pos.get.orient.y mustEqual 0f
shuttle.pos.get.orient.z mustEqual 180.0f
case _ =>
ko
}
}
"encode (droppod)" in {
val obj = DroppodData(
CommonFieldData(
PlacementData(5108.0f, 6164.0f, 1023.9844f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS,
2
)
)
val msg = ObjectCreateMessage(ObjectClass.droppod, PlanetSideGUID(3595), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_droppod
}
"encode (shuttle 1)" in {
val obj = OrbitalShuttleData(PlanetSideEmpire.VS)
val msg = ObjectCreateMessage(ObjectClass.orbital_shuttle, PlanetSideGUID(1129), ObjectCreateMessageParent(PlanetSideGUID(786), 3), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_orbital_shuttle_1
}
"encode (shuttle 2)" in {
val obj = OrbitalShuttleData(PlacementData(5610.0156f, 4255.258f, 134.1875f, 0f, 0f, 180.0f), PlanetSideEmpire.VS)
val msg = ObjectCreateMessage(ObjectClass.orbital_shuttle, PlanetSideGUID(1127), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_orbital_shuttle_2
}
}
}

View file

@ -0,0 +1,255 @@
// Copyright (c) 2017 PSForever
package game.objectcreatevehicle
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types._
import org.specs2.mutable._
import scodec.bits._
class NormalVehiclesTest extends Specification {
val string_fury = hex"17 50010000 A79 9D01 FBC1C 12A83 2F06 00 00 21 4400003FC00101140C800C0E40000004048F3600301900000"
val string_lightning = hex"17 8b010000 df1 5a00 6c2d7 65535 ca16 00 00 00 4400003fc00101300ad8040c4000000408190b801018000002617402070000000"
val string_mediumtransport = hex"17 DA010000 8A2 8301 FBC1C 12A83 2F06 00 00 21 2400003FC079020593F80C2E400000040410148030190000017458050D90000001010401F814064000000"
"Normal vehicles" should {
"decode (fury)" in {
PacketCoding.DecodePacket(string_fury).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 336
cls mustEqual ObjectClass.fury
guid mustEqual PlanetSideGUID(413)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val fury = data.get.asInstanceOf[VehicleData]
fury.basic.pos.coord.x mustEqual 6531.961f
fury.basic.pos.coord.y mustEqual 1872.1406f
fury.basic.pos.coord.z mustEqual 24.734375f
fury.basic.pos.orient.x mustEqual 0f
fury.basic.pos.orient.y mustEqual 0f
fury.basic.pos.orient.z mustEqual 357.1875f
fury.basic.pos.vel.isDefined mustEqual false
fury.basic.faction mustEqual PlanetSideEmpire.VS
fury.basic.unk mustEqual 2
fury.basic.player_guid mustEqual PlanetSideGUID(0)
fury.health mustEqual 255
//
fury.inventory.isDefined mustEqual true
fury.inventory.get.contents.size mustEqual 1
val mounting = fury.inventory.get.contents.head
mounting.objectClass mustEqual ObjectClass.fury_weapon_systema
mounting.guid mustEqual PlanetSideGUID(400)
mounting.parentSlot mustEqual 1
mounting.obj.isInstanceOf[WeaponData] mustEqual true
val weapon = mounting.obj.asInstanceOf[WeaponData]
weapon.unk1 mustEqual 0x6
weapon.unk2 mustEqual 0x8
weapon.fire_mode mustEqual 0
weapon.ammo.size mustEqual 1
val ammo = weapon.ammo.head
ammo.objectClass mustEqual ObjectClass.hellfire_ammo
ammo.guid mustEqual PlanetSideGUID(432)
ammo.parentSlot mustEqual 0
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8
case _ =>
ko
}
}
"decode (lightning)" in {
PacketCoding.DecodePacket(string_lightning).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 395L
cls mustEqual ObjectClass.lightning
guid mustEqual PlanetSideGUID(90)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val lightning = data.get.asInstanceOf[VehicleData]
lightning.basic.pos.coord.x mustEqual 3674.8438f
lightning.basic.pos.coord.y mustEqual 2726.789f
lightning.basic.pos.coord.z mustEqual 91.15625f
lightning.basic.pos.orient.x mustEqual 0f
lightning.basic.pos.orient.y mustEqual 0f
lightning.basic.pos.orient.z mustEqual 90.0f
lightning.basic.faction mustEqual PlanetSideEmpire.VS
lightning.basic.unk mustEqual 2
lightning.basic.player_guid mustEqual PlanetSideGUID(0)
lightning.health mustEqual 255
lightning.inventory.isDefined mustEqual true
lightning.inventory.get.contents.size mustEqual 1
val mounting = lightning.inventory.get.contents.head
mounting.objectClass mustEqual ObjectClass.lightning_weapon_system
mounting.guid mustEqual PlanetSideGUID(91)
mounting.parentSlot mustEqual 1
mounting.obj.isInstanceOf[WeaponData] mustEqual true
val weapon = mounting.obj.asInstanceOf[WeaponData]
weapon.unk1 mustEqual 0x4
weapon.unk2 mustEqual 0x8
weapon.fire_mode mustEqual 0
weapon.ammo.size mustEqual 2
//0
var ammo = weapon.ammo.head
ammo.objectClass mustEqual ObjectClass.bullet_75mm
ammo.guid mustEqual PlanetSideGUID(92)
ammo.parentSlot mustEqual 0
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x0
//1
ammo = weapon.ammo(1)
ammo.objectClass mustEqual ObjectClass.bullet_25mm
ammo.guid mustEqual PlanetSideGUID(93)
ammo.parentSlot mustEqual 1
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x0
case _ =>
ko
}
}
"decode (medium transport)" in {
PacketCoding.DecodePacket(string_mediumtransport).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 474L
cls mustEqual ObjectClass.mediumtransport
guid mustEqual PlanetSideGUID(387)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val deliverer = data.get.asInstanceOf[VehicleData]
deliverer.basic.pos.coord.x mustEqual 6531.961f
deliverer.basic.pos.coord.y mustEqual 1872.1406f
deliverer.basic.pos.coord.z mustEqual 24.734375f
deliverer.basic.pos.orient.x mustEqual 0f
deliverer.basic.pos.orient.y mustEqual 0f
deliverer.basic.pos.orient.z mustEqual 357.1875f
deliverer.basic.faction mustEqual PlanetSideEmpire.NC
deliverer.basic.unk mustEqual 2
deliverer.basic.player_guid mustEqual PlanetSideGUID(0)
deliverer.unk1 mustEqual 0
deliverer.health mustEqual 255
deliverer.unk2 mustEqual false
deliverer.driveState mustEqual DriveState.State7
deliverer.unk3 mustEqual true
deliverer.unk4 mustEqual None
deliverer.unk5 mustEqual false
deliverer.inventory.isDefined mustEqual true
deliverer.inventory.get.contents.size mustEqual 2
//0
var mounting = deliverer.inventory.get.contents.head
mounting.objectClass mustEqual ObjectClass.mediumtransport_weapon_systemA
mounting.guid mustEqual PlanetSideGUID(383)
mounting.parentSlot mustEqual 5
mounting.obj.isInstanceOf[WeaponData] mustEqual true
var weapon = mounting.obj.asInstanceOf[WeaponData]
weapon.unk1 mustEqual 0x6
weapon.unk2 mustEqual 0x8
weapon.fire_mode mustEqual 0
weapon.ammo.size mustEqual 1
var ammo = weapon.ammo.head
ammo.objectClass mustEqual ObjectClass.bullet_20mm
ammo.guid mustEqual PlanetSideGUID(420)
ammo.parentSlot mustEqual 0
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8
//1
mounting = deliverer.inventory.get.contents(1)
mounting.objectClass mustEqual ObjectClass.mediumtransport_weapon_systemB
mounting.guid mustEqual PlanetSideGUID(556)
mounting.parentSlot mustEqual 6
mounting.obj.isInstanceOf[WeaponData] mustEqual true
weapon = mounting.obj.asInstanceOf[WeaponData]
weapon.unk1 mustEqual 0x6
weapon.unk2 mustEqual 0x8
weapon.fire_mode mustEqual 0
weapon.ammo.size mustEqual 1
ammo = weapon.ammo.head
ammo.objectClass mustEqual ObjectClass.bullet_20mm
ammo.guid mustEqual PlanetSideGUID(575)
ammo.parentSlot mustEqual 0
ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8
case _ =>
ko
}
}
"encode (fury)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
PlanetSideEmpire.VS, 2
),
0,
255,
false, false,
DriveState.Mobile,
false, false, false,
None,
Some(InventoryData(
InventoryItemData(ObjectClass.fury_weapon_systema, PlanetSideGUID(400), 1,
WeaponData(0x6, 0x8, 0, ObjectClass.hellfire_ammo, PlanetSideGUID(432), 0, AmmoBoxData(0x8))
) :: Nil
))
)(VehicleFormat.Normal)
val msg = ObjectCreateMessage(ObjectClass.fury, PlanetSideGUID(413), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_fury
}
"encode (lightning)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 2
),
0,
255,
false, false,
DriveState.Mobile,
false, false, false,
None,
Some(InventoryData(
InventoryItemData(ObjectClass.lightning_weapon_system, PlanetSideGUID(91), 1,
WeaponData(4, 8, 0, ObjectClass.bullet_75mm, PlanetSideGUID(92), 0, AmmoBoxData(), ObjectClass.bullet_25mm, PlanetSideGUID(93), 1, AmmoBoxData())
) :: Nil
))
)(VehicleFormat.Normal)
val msg = ObjectCreateMessage(ObjectClass.lightning, PlanetSideGUID(90), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_lightning
}
"encode (medium transport)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
PlanetSideEmpire.NC, 2
),
0,
255,
false, false,
DriveState.State7,
true, false, false,
None,
Some(InventoryData(
InventoryItemData(ObjectClass.mediumtransport_weapon_systemA, PlanetSideGUID(383), 5,
WeaponData(6, 8, ObjectClass.bullet_20mm, PlanetSideGUID(420), 0, AmmoBoxData(8))
) ::
InventoryItemData(ObjectClass.mediumtransport_weapon_systemB, PlanetSideGUID(556), 6,
WeaponData(6, 8, ObjectClass.bullet_20mm, PlanetSideGUID(575), 0, AmmoBoxData(8))
) :: Nil
))
)(VehicleFormat.Normal)
val msg = ObjectCreateMessage(ObjectClass.mediumtransport, PlanetSideGUID(387), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_mediumtransport
}
}
}

View file

@ -0,0 +1,135 @@
// Copyright (c) 2017 PSForever
package game.objectcreatevehicle
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types._
import org.specs2.mutable._
import scodec.bits._
class UtilityVehiclesTest extends Specification {
val string_ant = hex"17 C2000000 9E0 7C01 6C2D7 65535 CA16 00 00 00 4400003FC000000"
val string_ams = hex"17 B8010000 970 3D10 002D765535CA16000000 402285BB0037E4100749E1D03000000620D83A0A00000195798741C00000332E40D84800000"
"Utility vehicles" should {
"decode (ant)" in {
PacketCoding.DecodePacket(string_ant).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 194L
cls mustEqual ObjectClass.ant
guid mustEqual PlanetSideGUID(380)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val ant = data.get.asInstanceOf[VehicleData]
ant.basic.pos.coord.x mustEqual 3674.8438f
ant.basic.pos.coord.y mustEqual 2726.789f
ant.basic.pos.coord.z mustEqual 91.15625f
ant.basic.pos.orient.x mustEqual 0f
ant.basic.pos.orient.y mustEqual 0f
ant.basic.pos.orient.z mustEqual 90.0f
ant.basic.faction mustEqual PlanetSideEmpire.VS
ant.basic.unk mustEqual 2
ant.basic.player_guid mustEqual PlanetSideGUID(0)
ant.health mustEqual 255
ant.driveState mustEqual DriveState.Mobile
case _ =>
ko
}
}
"decode (ams)" in {
PacketCoding.DecodePacket(string_ams).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 440L
cls mustEqual ObjectClass.ams
guid mustEqual PlanetSideGUID(4157)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val ams = data.get.asInstanceOf[VehicleData]
ams.basic.pos.coord.x mustEqual 3674.0f
ams.basic.pos.coord.y mustEqual 2726.789f
ams.basic.pos.coord.z mustEqual 91.15625f
ams.basic.pos.orient.x mustEqual 0f
ams.basic.pos.orient.y mustEqual 0f
ams.basic.pos.orient.z mustEqual 90.0f
ams.basic.faction mustEqual PlanetSideEmpire.VS
ams.basic.unk mustEqual 0
ams.basic.player_guid mustEqual PlanetSideGUID(34082)
ams.unk1 mustEqual 2
ams.health mustEqual 236
ams.unk2 mustEqual false
ams.driveState mustEqual DriveState.Deployed
ams.inventory.isDefined mustEqual true
val inv = ams.inventory.get.contents
inv.head.objectClass mustEqual ObjectClass.matrix_terminalc
inv.head.guid mustEqual PlanetSideGUID(3663)
inv.head.parentSlot mustEqual 1
inv.head.obj.isInstanceOf[CommonTerminalData] mustEqual true
inv(1).objectClass mustEqual ObjectClass.ams_respawn_tube
inv(1).guid mustEqual PlanetSideGUID(3638)
inv(1).parentSlot mustEqual 2
inv(1).obj.isInstanceOf[CommonTerminalData] mustEqual true
inv(2).objectClass mustEqual ObjectClass.order_terminala
inv(2).guid mustEqual PlanetSideGUID(3827)
inv(2).parentSlot mustEqual 3
inv(2).obj.isInstanceOf[CommonTerminalData] mustEqual true
inv(3).objectClass mustEqual ObjectClass.order_terminalb
inv(3).guid mustEqual PlanetSideGUID(3556)
inv(3).parentSlot mustEqual 4
inv(3).obj.isInstanceOf[CommonTerminalData] mustEqual true
case _ =>
ko
}
}
"encode (ant)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 2
),
0,
255,
false, false,
DriveState.Mobile,
false, false, false,
Some(UtilityVehicleData(0)),
None
)(VehicleFormat.Utility)
val msg = ObjectCreateMessage(ObjectClass.ant, PlanetSideGUID(380), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ant
}
"encode (ams)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(3674.0f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 0,
PlanetSideGUID(34082)
),
2,
236,
false, false,
DriveState.Deployed,
false, true, true,
Some(UtilityVehicleData(60)), //what does this mean?
Some(InventoryData(List(
InternalSlot(ObjectClass.matrix_terminalc, PlanetSideGUID(3663), 1, CommonTerminalData(PlanetSideEmpire.VS)),
InternalSlot(ObjectClass.ams_respawn_tube, PlanetSideGUID(3638), 2, CommonTerminalData(PlanetSideEmpire.VS)),
InternalSlot(ObjectClass.order_terminala, PlanetSideGUID(3827), 3, CommonTerminalData(PlanetSideEmpire.VS)),
InternalSlot(ObjectClass.order_terminalb, PlanetSideGUID(3556), 4, CommonTerminalData(PlanetSideEmpire.VS))
)))
)(VehicleFormat.Utility)
val msg = ObjectCreateMessage(ObjectClass.ams, PlanetSideGUID(4157), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ams
}
}
}

View file

@ -0,0 +1,87 @@
// Copyright (c) 2017 PSForever
package game.objectcreatevehicle
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types._
import org.specs2.mutable._
import scodec.bits._
class VariantVehiclesTest extends Specification {
val string_switchblade = hex"17 93010000 A7B A201 FBC1C12A832F06000021 4400003FC00001013AD3180C0E4000000408330DC03019000006620406072000000"
"Variant vehicles" should {
"decode (switchblade)" in {
PacketCoding.DecodePacket(string_switchblade).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
len mustEqual 403L
cls mustEqual ObjectClass.switchblade
guid mustEqual PlanetSideGUID(418)
parent.isDefined mustEqual false
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val switchblade = data.get.asInstanceOf[VehicleData]
switchblade.basic.pos.coord.x mustEqual 6531.961f
switchblade.basic.pos.coord.y mustEqual 1872.1406f
switchblade.basic.pos.coord.z mustEqual 24.734375f
switchblade.basic.pos.orient.x mustEqual 0f
switchblade.basic.pos.orient.y mustEqual 0f
switchblade.basic.pos.orient.z mustEqual 357.1875f
switchblade.basic.faction mustEqual PlanetSideEmpire.VS
switchblade.basic.unk mustEqual 2
switchblade.health mustEqual 255
switchblade.driveState mustEqual DriveState.Mobile
switchblade.inventory.isDefined mustEqual true
switchblade.inventory.get.contents.size mustEqual 1
//0
val weapon = switchblade.inventory.get.contents.head
weapon.objectClass mustEqual ObjectClass.scythe
weapon.guid mustEqual PlanetSideGUID(355)
weapon.parentSlot mustEqual 1
weapon.obj.asInstanceOf[WeaponData].unk1 mustEqual 0x6
weapon.obj.asInstanceOf[WeaponData].unk2 mustEqual 0x8
weapon.obj.asInstanceOf[WeaponData].ammo.size mustEqual 2
//ammo-0
var ammo = weapon.obj.asInstanceOf[WeaponData].ammo.head
ammo.objectClass mustEqual ObjectClass.ancient_ammo_vehicle
ammo.guid mustEqual PlanetSideGUID(366)
ammo.parentSlot mustEqual 0
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8
//ammo-1
ammo = weapon.obj.asInstanceOf[WeaponData].ammo(1)
ammo.objectClass mustEqual ObjectClass.ancient_ammo_vehicle
ammo.guid mustEqual PlanetSideGUID(385)
ammo.parentSlot mustEqual 1
ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8
case _ =>
ko
}
}
"encode (switchblade)" in {
val obj = VehicleData(
CommonFieldData(
PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
PlanetSideEmpire.VS,
2
),
0,
255,
false, false,
DriveState.Mobile,
false, false, false,
Some(VariantVehicleData(0)),
Some(InventoryData(
InventoryItemData(ObjectClass.scythe, PlanetSideGUID(355), 1,
WeaponData(0x6, 0x8, 0, ObjectClass.ancient_ammo_vehicle, PlanetSideGUID(366), 0, AmmoBoxData(0x8), ObjectClass.ancient_ammo_vehicle, PlanetSideGUID(385), 1, AmmoBoxData(0x8))
) :: Nil
))
)(VehicleFormat.Variant)
val msg = ObjectCreateMessage(ObjectClass.switchblade, PlanetSideGUID(418), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_switchblade
}
}
}

View file

@ -149,7 +149,8 @@ class ConverterTest extends Specification {
val tool = Tool(tdef) val tool = Tool(tdef)
tool.GUID = PlanetSideGUID(92) tool.GUID = PlanetSideGUID(92)
tool.AmmoSlot.Box.GUID = PlanetSideGUID(90) tool.AmmoSlot.Box.GUID = PlanetSideGUID(90)
val obj = Player(PlanetSideGUID(93), "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) val obj = Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.GUID = PlanetSideGUID(93)
obj.Slot(2).Equipment = tool obj.Slot(2).Equipment = tool
obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(94) obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(94)
obj.Inventory += 8 -> AmmoBox(GlobalDefinitions.bullet_9mm) obj.Inventory += 8 -> AmmoBox(GlobalDefinitions.bullet_9mm)

View file

@ -10,6 +10,21 @@ import net.psforever.objects.GlobalDefinitions._
import org.specs2.mutable._ import org.specs2.mutable._
class EquipmentTest extends Specification { class EquipmentTest extends Specification {
"EquipmentSize" should {
"equal" in {
//basic equality
EquipmentSize.isEqual(EquipmentSize.Pistol, EquipmentSize.Pistol) mustEqual true
EquipmentSize.isEqual(EquipmentSize.Pistol, EquipmentSize.Rifle) mustEqual false
//Inventory is always allowed
EquipmentSize.isEqual(EquipmentSize.Inventory, EquipmentSize.Rifle) mustEqual true
EquipmentSize.isEqual(EquipmentSize.Pistol, EquipmentSize.Inventory) mustEqual true
//Blocked is never allowed
EquipmentSize.isEqual(EquipmentSize.Blocked, EquipmentSize.Rifle) mustEqual false
EquipmentSize.isEqual(EquipmentSize.Pistol, EquipmentSize.Blocked) mustEqual false
EquipmentSize.isEqual(EquipmentSize.Blocked, EquipmentSize.Inventory) mustEqual false
}
}
"AmmoBox" should { "AmmoBox" should {
"define" in { "define" in {
val obj = AmmoBoxDefinition(86) val obj = AmmoBoxDefinition(86)
@ -59,13 +74,13 @@ class EquipmentTest extends Specification {
obj.Size = EquipmentSize.Rifle obj.Size = EquipmentSize.Rifle
obj.AmmoTypes += GlobalDefinitions.shotgun_shell obj.AmmoTypes += GlobalDefinitions.shotgun_shell
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
obj.FireModes += new FireModeDefinition obj.FireModes += FireModeDefinition()
obj.FireModes.head.AmmoTypeIndices += 0 obj.FireModes.head.AmmoTypeIndices += 0
obj.FireModes.head.AmmoTypeIndices += 1 obj.FireModes.head.AmmoTypeIndices += 1
obj.FireModes.head.AmmoSlotIndex = 0 obj.FireModes.head.AmmoSlotIndex = 0
obj.FireModes.head.Magazine = 18 obj.FireModes.head.Magazine = 18
obj.FireModes.head.ResetAmmoIndexOnSwap = true obj.FireModes.head.ResetAmmoIndexOnSwap = true
obj.FireModes += new FireModeDefinition obj.FireModes += FireModeDefinition()
obj.FireModes(1).AmmoTypeIndices += 0 obj.FireModes(1).AmmoTypeIndices += 0
obj.FireModes(1).AmmoTypeIndices += 1 obj.FireModes(1).AmmoTypeIndices += 1
obj.FireModes(1).AmmoSlotIndex = 1 obj.FireModes(1).AmmoSlotIndex = 1

View file

@ -1,9 +1,10 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package objects package objects
import net.psforever.objects.{Player, SimpleItem} import net.psforever.objects._
import net.psforever.objects.definition.{ImplantDefinition, SimpleItemDefinition} import net.psforever.objects.definition.{ImplantDefinition, SimpleItemDefinition}
import net.psforever.objects.equipment.EquipmentSize import net.psforever.objects.equipment.EquipmentSize
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.{CharacterGender, ExoSuitType, ImplantType, PlanetSideEmpire} import net.psforever.types.{CharacterGender, ExoSuitType, ImplantType, PlanetSideEmpire}
import org.specs2.mutable._ import org.specs2.mutable._
@ -13,17 +14,55 @@ class PlayerTest extends Specification {
obj.isAlive mustEqual false obj.isAlive mustEqual false
} }
"different players" in {
(Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)) mustEqual true
(Player("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
Player("Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)) mustEqual false
(Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
Player("Chord", PlanetSideEmpire.NC, CharacterGender.Male, 0, 5)) mustEqual false
(Player("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
Player("Chord2", PlanetSideEmpire.TR, CharacterGender.Female, 0, 5)) mustEqual false
(Player("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
Player("Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 1, 5)) mustEqual false
(Player("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
Player("Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 6)) mustEqual false
}
"become a backpack" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.isAlive mustEqual false
obj.isBackpack mustEqual false
obj.Release
obj.isAlive mustEqual false
obj.isBackpack mustEqual true
}
"(re)spawn" in { "(re)spawn" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.isAlive mustEqual false obj.isAlive mustEqual false
obj.Health mustEqual 0 obj.Health mustEqual 0
obj.Stamina mustEqual 0 obj.Stamina mustEqual 0
obj.Armor mustEqual 0 obj.Armor mustEqual 0
obj.MaxHealth mustEqual 100
obj.MaxStamina mustEqual 100
obj.MaxArmor mustEqual 50
obj.Spawn obj.Spawn
obj.isAlive mustEqual true obj.isAlive mustEqual true
obj.Health mustEqual obj.MaxHealth obj.Health mustEqual 100
obj.Stamina mustEqual obj.MaxStamina obj.Stamina mustEqual 100
obj.Armor mustEqual obj.MaxArmor obj.Armor mustEqual 50
}
"set new maximum values (health, stamina)" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.MaxHealth mustEqual 100
obj.MaxStamina mustEqual 100
obj.MaxHealth = 123
obj.MaxStamina = 456
obj.Spawn
obj.Health mustEqual 123
obj.Stamina mustEqual 456
} }
"init (Standard Exo-Suit)" in { "init (Standard Exo-Suit)" in {
@ -106,6 +145,40 @@ class PlayerTest extends Specification {
obj.LastDrawnSlot mustEqual 1 obj.LastDrawnSlot mustEqual 1
} }
"hold something in their free hand" in {
val wep = SimpleItem(SimpleItemDefinition(149))
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Slot(Player.FreeHandSlot).Equipment = wep
obj.Slot(Player.FreeHandSlot).Equipment.get.Definition.ObjectId mustEqual 149
}
"provide an invalid hand that can not hold anything" in {
val wep = SimpleItem(SimpleItemDefinition(149))
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Slot(-1).Equipment = wep
obj.Slot(-1).Equipment mustEqual None
}
"search for the smallest available slot in which to satore equipment" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Inventory.Resize(3,3)
obj.Fit(Tool(GlobalDefinitions.beamer)) mustEqual Some(0)
obj.Fit(Tool(GlobalDefinitions.suppressor)) mustEqual Some(2)
val ammo = AmmoBox(GlobalDefinitions.bullet_9mm)
val ammo2 = AmmoBox(GlobalDefinitions.bullet_9mm)
val ammo3 = AmmoBox(GlobalDefinitions.bullet_9mm)
obj.Fit(ammo) mustEqual Some(6)
obj.Slot(6).Equipment = ammo
obj.Fit(ammo2) mustEqual Some(Player.FreeHandSlot)
obj.Slot(Player.FreeHandSlot).Equipment = ammo2
obj.Fit(ammo2) mustEqual None
}
"install an implant" in { "install an implant" in {
val testplant : ImplantDefinition = ImplantDefinition(1) val testplant : ImplantDefinition = ImplantDefinition(1)
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
@ -141,6 +214,31 @@ class PlayerTest extends Specification {
obj.Implants(0).Installed mustEqual None obj.Implants(0).Installed mustEqual None
} }
"seat in a vehicle" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.VehicleSeated mustEqual None
obj.VehicleSeated = PlanetSideGUID(65)
obj.VehicleSeated mustEqual Some(PlanetSideGUID(65))
obj.VehicleSeated = None
obj.VehicleSeated mustEqual None
}
"own in a vehicle" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.VehicleOwned mustEqual None
obj.VehicleOwned = PlanetSideGUID(65)
obj.VehicleOwned mustEqual Some(PlanetSideGUID(65))
obj.VehicleOwned = None
obj.VehicleOwned mustEqual None
}
"remember what zone he is in" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Continent mustEqual "home2"
obj.Continent = "ugd01"
obj.Continent mustEqual "ugd01"
}
"administrate" in { "administrate" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Admin mustEqual false obj.Admin mustEqual false

View file

@ -57,7 +57,7 @@ class VehicleSpawnControl2Test extends ActorTest() {
assert(reply2.asInstanceOf[VehicleSpawnPad.LoadVehicle].vehicle == vehicle) assert(reply2.asInstanceOf[VehicleSpawnPad.LoadVehicle].vehicle == vehicle)
assert(reply2.asInstanceOf[VehicleSpawnPad.LoadVehicle].pad == obj) assert(reply2.asInstanceOf[VehicleSpawnPad.LoadVehicle].pad == obj)
player.VehicleOwned = vehicle player.VehicleOwned = Some(vehicle.GUID)
val reply3 = receiveOne(Duration.create(10000, "ms")) val reply3 = receiveOne(Duration.create(10000, "ms"))
assert(reply3.isInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle]) assert(reply3.isInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle])
assert(reply3.asInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle].vehicle == vehicle) assert(reply3.asInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle].vehicle == vehicle)

View file

@ -281,5 +281,43 @@ class NumberPoolHubTest extends Specification {
val hub = new NumberPoolHub(src) val hub = new NumberPoolHub(src)
hub.unregister(4).isFailure mustEqual true hub.unregister(4).isFailure mustEqual true
} }
"identity an object that is registered to it" in {
val hub1 = new NumberPoolHub(new LimitedNumberSource(10))
val hub2 = new NumberPoolHub(new LimitedNumberSource(10))
val obj1 = new EntityTestClass()
val obj2 = new EntityTestClass()
hub1.register(obj1)
hub2.register(obj2)
hub1.isRegistered(obj1) mustEqual true
hub2.isRegistered(obj2) mustEqual true
hub1.isRegistered(obj2) mustEqual false
hub2.isRegistered(obj1) mustEqual false
}
"identity a number that is registered to it" in {
val src1 = new LimitedNumberSource(5)
val hub1 = new NumberPoolHub(src1)
val src2 = new LimitedNumberSource(10)
src2.Restrict(0)
src2.Restrict(1)
src2.Restrict(2)
src2.Restrict(3)
src2.Restrict(4)
src2.Restrict(5)
val hub2 = new NumberPoolHub(src2)
val obj1 = new EntityTestClass()
val obj2 = new EntityTestClass()
hub1.register(obj1)
hub2.register(obj2)
val num1 = obj1.GUID.guid
val num2 = obj2.GUID.guid
hub1.isRegistered(num1) mustEqual true
hub2.isRegistered(num2) mustEqual true
hub1.isRegistered(num2) mustEqual false
hub2.isRegistered(num1) mustEqual false
}
} }
} }

View file

@ -16,6 +16,14 @@ class NumberPoolTest extends Specification {
ok ok
} }
"fail to construct 1 (number less than zero)" in {
new SimplePool(-1 :: Nil) must throwA[IllegalArgumentException]
}
"fail to construct 2 (duplicate numbers)" in {
new SimplePool(1 :: 1 :: Nil) must throwA[IllegalArgumentException]
}
"get a number" in { "get a number" in {
val obj = new SimplePool((0 to 10).toList) val obj = new SimplePool((0 to 10).toList)
obj.Get() match { obj.Get() match {
@ -26,6 +34,13 @@ class NumberPoolTest extends Specification {
} }
} }
"used number count is always zero" in {
val obj = new SimplePool((0 to 10).toList)
obj.Count mustEqual 0
obj.Get()
obj.Count mustEqual 0
}
"return a number" in { "return a number" in {
//returning a number for a SimplePool is actually just a way of checking that the number is in the "pool" at all //returning a number for a SimplePool is actually just a way of checking that the number is in the "pool" at all
val obj = new SimplePool((0 to 10).toList) val obj = new SimplePool((0 to 10).toList)

View file

@ -3,6 +3,7 @@ package objects.number
import net.psforever.objects.guid.AvailabilityPolicy import net.psforever.objects.guid.AvailabilityPolicy
import net.psforever.objects.guid.key.{LoanedKey, SecureKey} import net.psforever.objects.guid.key.{LoanedKey, SecureKey}
import net.psforever.packet.game.PlanetSideGUID
import org.specs2.mutable.Specification import org.specs2.mutable.Specification
class NumberSourceTest extends Specification { class NumberSourceTest extends Specification {
@ -102,6 +103,17 @@ class NumberSourceTest extends Specification {
result2.get.Object mustEqual Some(test) result2.get.Object mustEqual Some(test)
} }
"return a secure key" in {
val obj = LimitedNumberSource(25)
val test = new TestClass()
val result1 : Option[LoanedKey] = obj.Available(5)
result1.get.Object = test
test.GUID = PlanetSideGUID(5)
val result2 : Option[SecureKey] = obj.Get(5)
obj.Return(result2.get) mustEqual Some(test)
}
"restrict a previously-assigned number" in { "restrict a previously-assigned number" in {
val obj = LimitedNumberSource(25) val obj = LimitedNumberSource(25)
val test = new TestClass() val test = new TestClass()

View file

@ -0,0 +1,60 @@
// Copyright (c) 2017 PSForever
package objects.number
import akka.actor.Actor
import net.psforever.objects.guid.actor.Register
import org.specs2.mutable.Specification
class RegisterTest extends Specification {
val obj = new net.psforever.objects.entity.IdentifiableEntity() {}
"Register" should {
"construct (object)" in {
val reg = Register(obj)
reg.obj mustEqual obj
reg.number mustEqual None
reg.name mustEqual None
reg.callback mustEqual None
}
"construct (object, callback)" in {
val reg = Register(obj, Actor.noSender)
reg.obj mustEqual obj
reg.number mustEqual None
reg.name mustEqual None
reg.callback mustEqual Some(Actor.noSender)
}
"construct (object, suggested number)" in {
val reg = Register(obj, 5)
reg.obj mustEqual obj
reg.number mustEqual Some(5)
reg.name mustEqual None
reg.callback mustEqual None
}
"construct (object, suggested number, callback)" in {
val reg = Register(obj, 5, Actor.noSender)
reg.obj mustEqual obj
reg.number mustEqual Some(5)
reg.name mustEqual None
reg.callback mustEqual Some(Actor.noSender)
}
"construct (object, pool name)" in {
val reg = Register(obj, "pool")
reg.obj mustEqual obj
reg.number mustEqual None
reg.name mustEqual Some("pool")
reg.callback mustEqual None
}
"construct (object, pool name, callback)" in {
val reg = Register(obj, "pool", Actor.noSender)
reg.obj mustEqual obj
reg.number mustEqual None
reg.name mustEqual Some("pool")
reg.callback mustEqual Some(Actor.noSender)
}
}
}

View file

@ -10,7 +10,7 @@ import objects.ActorTest
import scala.concurrent.duration.Duration import scala.concurrent.duration.Duration
class TerminalControlTest extends ActorTest() { class TerminalControl1Test extends ActorTest() {
"TerminalControl" should { "TerminalControl" should {
"construct (cert terminal)" in { "construct (cert terminal)" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal) val terminal = Terminal(GlobalDefinitions.cert_terminal)
@ -19,6 +19,17 @@ class TerminalControlTest extends ActorTest() {
} }
} }
class TerminalControl2Test extends ActorTest() {
"TerminalControl can not process wrong messages" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-cert-term")
terminal.Actor !"hello"
val reply = receiveOne(Duration.create(500, "ms"))
assert(reply.isInstanceOf[Terminal.NoDeal])
}
}
//terminal control is mostly a pass-through actor for Terminal.Exchange messages, wrapped in Terminal.TerminalMessage protocol //terminal control is mostly a pass-through actor for Terminal.Exchange messages, wrapped in Terminal.TerminalMessage protocol
//test for Cert_Terminal messages (see CertTerminalTest) //test for Cert_Terminal messages (see CertTerminalTest)
class CertTerminalControl1Test extends ActorTest() { class CertTerminalControl1Test extends ActorTest() {

View file

@ -120,10 +120,6 @@ class PacketCodingActor extends Actor with MDCContextAware {
// failWithError(s"Invalid message '$default' received in state Established") // failWithError(s"Invalid message '$default' received in state Established")
} }
def resetState() : Unit = {
context.become(receive)
}
/** /**
* Retrieve the current subslot number. * Retrieve the current subslot number.
* Increment the `subslot` for the next time it is needed. * Increment the `subslot` for the next time it is needed.

View file

@ -199,7 +199,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
sendResponse(PacketCoding.CreateGamePacket(0, ObjectHeldMessage(guid, slot, true))) sendResponse(PacketCoding.CreateGamePacket(0, ObjectHeldMessage(guid, slot, true)))
} }
case AvatarResponse.PlanetSideAttribute(attribute_type, attribute_value) => case AvatarResponse.PlanetsideAttribute(attribute_type, attribute_value) =>
if(player.GUID != guid) { if(player.GUID != guid) {
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(guid, attribute_type, attribute_value))) sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(guid, attribute_type, attribute_value)))
} }

View file

@ -19,7 +19,7 @@ object AvatarResponse {
// final case class LoadMap() extends Response // final case class LoadMap() extends Response
final case class ObjectDelete(item_guid : PlanetSideGUID, unk : Int) extends Response final case class ObjectDelete(item_guid : PlanetSideGUID, unk : Int) extends Response
final case class ObjectHeld(slot : Int) extends Response final case class ObjectHeld(slot : Int) extends Response
final case class PlanetSideAttribute(attribute_type : Int, attribute_value : Long) extends Response final case class PlanetsideAttribute(attribute_type : Int, attribute_value : Long) extends Response
final case class PlayerState(msg : PlayerStateMessageUpstream, spectator : Boolean, weaponInHand : Boolean) extends Response final case class PlayerState(msg : PlayerStateMessageUpstream, spectator : Boolean, weaponInHand : Boolean) extends Response
final case class Reload(mag : Int) extends Response final case class Reload(mag : Int) extends Response
// final case class PlayerStateShift(itemID : PlanetSideGUID) extends Response // final case class PlayerStateShift(itemID : PlanetSideGUID) extends Response

View file

@ -59,7 +59,7 @@ class AvatarService extends Actor {
) )
case AvatarAction.PlanetsideAttribute(guid, attribute_type, attribute_value) => case AvatarAction.PlanetsideAttribute(guid, attribute_type, attribute_value) =>
AvatarEvents.publish( AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlanetSideAttribute(attribute_type, attribute_value)) AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlanetsideAttribute(attribute_type, attribute_value))
) )
case AvatarAction.PlayerState(guid, msg, spectator, weapon) => case AvatarAction.PlayerState(guid, msg, spectator, weapon) =>
AvatarEvents.publish( AvatarEvents.publish(

View file

@ -0,0 +1,57 @@
// Copyright (c) 2017 PSForever
import akka.actor.{ActorRef, ActorSystem, MDCContextAware}
import akka.testkit.{ImplicitSender, TestKit, TestProbe}
import net.psforever.packet.{ControlPacket, GamePacket}
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
import org.specs2.specification.Scope
abstract class ActorTest(sys : ActorSystem = ActorSystem("system")) extends TestKit(sys) with Scope with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll {
override def afterAll {
TestKit.shutdownActorSystem(system)
}
}
object ActorTest {
final case class MDCGamePacket(packet : GamePacket)
final case class MDCControlPacket(packet : ControlPacket)
class MDCTestProbe(probe : TestProbe) extends MDCContextAware {
/*
The way this test mediator works needs to be explained.
MDCContextAware objects initialize themselves in a chain of ActorRefs defined in the HelloFriend message.
As the iterator is consumed, it produces a right-neighbor (r-neighbor) that is much further along the chain.
The HelloFriend is passed to that r-neighbor and that is how subsequent neighbors are initialized and chained.
MDCContextAware objects consume and produce internal messages called MdcMsg that wrap around the payload.
Normally inaccessible from the outside, the payload is unwrapped within the standard receive PartialFunction.
By interacting with a TestProbe constructor param, information that would be concealed by MdcMsg can be polled.
The l-neighbor of the MDCContextAware is the system of the ActorTest TestKit.
The r-neighbor of the MDCContextAware is this MDCTestProbe and, indirectly, the TestProbe that was interjected.
Pass l-input into the MDCContextAware itself.
The r-output is a normal message that can be polled on that TestProbe.
Pass r-input into this MDCTestProbe directly.
The l-output is an MdcMsg that can be treated just as r-output, sending it to this Actor and polling the TestProbe.
*/
private var left : ActorRef = ActorRef.noSender
def receive : Receive = {
case msg @ HelloFriend(_, _) =>
left = sender()
probe.ref ! msg
case MDCGamePacket(msg) =>
left ! msg
case MDCControlPacket(msg) =>
left ! msg
case msg =>
left ! msg
probe.ref ! msg
}
}
}

View file

@ -0,0 +1,187 @@
// Copyright (c) 2017 PSForever
import akka.actor.Props
import net.psforever.objects._
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
import net.psforever.types.{CharacterGender, ExoSuitType, PlanetSideEmpire, Vector3}
import services.Service
import services.avatar._
class AvatarService0Test extends ActorTest {
"AvatarService" should {
"construct" in {
system.actorOf(Props[AvatarService], "service")
assert(true)
}
}
}
class AvatarService1ATest extends ActorTest {
"AvatarService" should {
"subscribe" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
assert(true)
}
}
}
class AvatarService1BTest extends ActorTest {
"AvatarService" should {
"subscribe" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! Service.Leave()
assert(true)
}
}
}
class AvatarService1CTest extends ActorTest {
"AvatarService" should {
"subscribe" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! Service.LeaveAll()
assert(true)
}
}
}
class AvatarService2Test extends ActorTest {
"AvatarService" should {
"pass an unhandled message" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! "hello"
expectNoMsg()
}
}
}
class AvatarService3Test extends ActorTest {
"AvatarService" should {
"pass ArmorChanged" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ArmorChanged(PlanetSideGUID(10), ExoSuitType.Reinforced, 0))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ArmorChanged(ExoSuitType.Reinforced, 0)))
}
}
}
class AvatarService4Test extends ActorTest {
"AvatarService" should {
"pass ConcealPlayer" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ConcealPlayer(PlanetSideGUID(10)))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ConcealPlayer()))
}
}
}
class AvatarService5Test extends ActorTest {
val tool = Tool(GlobalDefinitions.beamer)
"AvatarService" should {
"pass EquipmentInHand" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.EquipmentInHand(PlanetSideGUID(10), 2, tool))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.EquipmentInHand(2, tool)))
}
}
}
class AvatarService6Test extends ActorTest {
val tool = Tool(GlobalDefinitions.beamer)
"AvatarService" should {
"pass EquipmentOnGround" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.EquipmentOnGround(PlanetSideGUID(10), Vector3(300f, 200f, 100f), Vector3(450f, 300f, 150f), tool))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.EquipmentOnGround(Vector3(300f, 200f, 100f), Vector3(450f, 300f, 150f), tool)))
}
}
}
class AvatarService7Test extends ActorTest {
val obj = Player("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, 1)
obj.GUID = PlanetSideGUID(10)
obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(11)
val pdata = obj.Definition.Packet.DetailedConstructorData(obj).get
"AvatarService" should {
"pass LoadPlayer" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.LoadPlayer(PlanetSideGUID(10), pdata))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.LoadPlayer(pdata)))
}
}
}
class AvatarService8Test extends ActorTest {
"AvatarService" should {
"pass ObjectDelete" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(10), PlanetSideGUID(11)))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(PlanetSideGUID(11), 0)))
service ! AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(10), PlanetSideGUID(11), 55))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(PlanetSideGUID(11), 55)))
}
}
}
class AvatarService9Test extends ActorTest {
"AvatarService" should {
"pass ObjectHeld" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ObjectHeld(PlanetSideGUID(10), 1))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectHeld(1)))
}
}
}
class AvatarServiceATest extends ActorTest {
"AvatarService" should {
"pass PlanetsideAttribute" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.PlanetsideAttribute(PlanetSideGUID(10), 5, 1200L))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PlanetsideAttribute(5, 1200L)))
}
}
}
class AvatarServiceBTest extends ActorTest {
val msg = PlayerStateMessageUpstream(PlanetSideGUID(75), Vector3(3694.1094f, 2735.4531f, 90.84375f), Some(Vector3(4.375f, 2.59375f, 0.0f)), 61.875f, 351.5625f, 0.0f, 136, 0, false, false, false, false, 112, 0)
"AvatarService" should {
"pass PlayerState" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.PlayerState(PlanetSideGUID(10), msg, false, false))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PlayerState(msg, false, false)))
}
}
}
class AvatarServiceCTest extends ActorTest {
"AvatarService" should {
"pass Reload" in {
val service = system.actorOf(Props[AvatarService], "service")
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.Reload(PlanetSideGUID(10), 35))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.Reload(35)))
}
}
}
object AvatarServiceTest {
//decoy
}

File diff suppressed because one or more lines are too long